Railway Operation Simulator  v2.13.0 Beta
A railway simulator for Windows
InterfaceUnit.cpp
Go to the documentation of this file.
1 // InterfaceUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 
27 #include <Classes.hpp>
28 #include <Controls.hpp>
29 #include <StdCtrls.hpp>
30 #include <Forms.hpp>
31 #include <Buttons.hpp>
32 #include <ExtCtrls.hpp>
33 #include <Menus.hpp>
34 #include <Dialogs.hpp>
35 #include <Graphics.hpp>
36 #include <ComCtrls.hpp>
37 #include <Clipbrd.hpp> //for selection clipboard functions at v2.8.0
38 #include <fstream>
39 #include <sstream> //for clipboard functions at v2.8.0
40 #include <vector>
41 #include <vcl.h>
42 #include <stdio.h>
43 #include <algorithm> //for sort
44 
45 #pragma hdrstop
46 // The above batch of include files above #pragma hdrstop appear in all .cpp files.
47 // They aren't all needed in each case but being together and identical they speed
48 // up compilation considerably (without ~14 min, with ~1 min!). They are used in
49 // conjunction with 'use pre-compiled headers' in the project compiler options.
50 
51 #include "InterfaceUnit.h"
52 #include "GraphicUnit.h"
53 #include "DisplayUnit.h"
54 #include "TextUnit.h"
55 #include "TrainUnit.h"
56 #include "Utilities.h"
57 #include "TrackUnit.h"
58 #include "AboutUnit.h"
59 #include "API.h" //added at v2.10.0
60 #include <dirent.h>
61 #include <Filectrl.hpp> //to check whether directories exist
62 
63 // ---------------------------------------------------------------------------
64 #include <Vcl.HTMLHelpViewer.hpp> //added at v2.0.0 for access to the .chm help file
65 #pragma package(smart_init)
66 #pragma link "Vcl.HTMLHelpViewer" //added at v2.0.0 for access to the .chm help file
67 #pragma resource "*.dfm"
68 
70 API *session_api_; //moved from header to avoid AboutForm having access and defining _session_api_
71  //as well as Interface and giving a warning, added at v2.10.0
72 
73 // Folder Names
74 const UnicodeString TInterface::RAILWAY_DIR_NAME = "Railways";
75 const UnicodeString TInterface::TIMETABLE_DIR_NAME = "Program timetables";
76 const UnicodeString TInterface::PERFLOG_DIR_NAME = "Performance logs";
77 const UnicodeString TInterface::SESSION_DIR_NAME = "Sessions";
78 const UnicodeString TInterface::IMAGE_DIR_NAME = "Images";
79 const UnicodeString TInterface::FORMATTEDTT_DIR_NAME = "Formatted timetables";
80 const UnicodeString TInterface::USERGRAPHICS_DIR_NAME = "Graphics";
81 
82 // ---------------------------------------------------------------------------
83 
84 __fastcall TInterface::TInterface(TComponent* Owner) : TForm(Owner)
85 {
86  // constructor
87  try
88  {
89  Screen->Cursor = TCursor(-11); // Hourglass
90  DirOpenError = false;
91  AllSetUpFlag = false; // flag to prevent MasterClock from being enabled when application activates if there has been an error during
92  // initial setup
93  // MasterClock->Enabled = false;//keep this stopped until all set up (no effect here as form not yet created, made false in object insp)
94  // Visible = false; //keep the Interface form invisible until all set up (no effect here as form not yet created, made false in object insp)
95  ProgramVersion = GetVersion() + " Beta";
96  // use GNU Major/Minor/Patch version numbering system, change for each published modification, Dev x = interim internal
97  // development stages (don't show on published versions)
98 
99  // check for presence of directories, creation failure probably indicates that the
100  // working folder is read-only
101 
102  CurDir = AnsiString(GetCurrentDir());
103 // ShowMessage("Curdir from GetCurrentDir() " + CurDir); //these used to check behaviour outside the compiler
104  UnicodeString FullProgramName = GetModuleName(0); // added at v2.9.0 to check executable exists
105 // ShowMessage("FullProgramName " + FullProgramName);
106  UnicodeString ProgramName = ExtractFileName(FullProgramName); // as above
107 // ShowMessage("ProgramName " + ProgramName);
108  UnicodeString ProgramDirectoryName = ExtractFilePath(FullProgramName); // as above
109 // ShowMessage("ProgramDirectoryName " + ProgramDirectoryName);
110 
111  if(!FileExists(ProgramName)) //added at v2.9.0 after discovering the effect described below
112  {
113  if(!SetCurrentDir(ProgramDirectoryName)) //if false the current directory couldn't be changed
114  {
115  ShowMessage("The working directory does not contain the railway executable file so the program cannot "
116  "open. This is usually because the program has been selected via the right-click taskbar icon though it may "
117  "also happen in other circumstances. It is caused by the Windows operating system re-assigning the "
118  "working directory for some unknown reason, though whether or not it happens appears to depend on the "
119  "Windows update version.\n\n"
120  "To avoid this happening please open the program by double clicking the program icon on the desktop "
121  "if there is one, or the program icon shown in Windows Explorer.");
122  Application->Terminate();
123  }
124  else
125  {
126  CurDir = AnsiString(GetCurrentDir());
127  }
128  }
129 
130  if(!DirectoryExists(RAILWAY_DIR_NAME))
131  {
132  if(!CreateDir(RAILWAY_DIR_NAME))
133  {
134  DirOpenError = true;
135  }
136 
137  }
138  if(!DirectoryExists(TIMETABLE_DIR_NAME))
139  {
140  if(!CreateDir(TIMETABLE_DIR_NAME))
141  {
142  DirOpenError = true;
143  }
144  }
145  if(!DirectoryExists(PERFLOG_DIR_NAME))
146  {
147  if(!CreateDir(PERFLOG_DIR_NAME))
148  {
149  DirOpenError = true;
150  }
151  }
152  if(!DirectoryExists(SESSION_DIR_NAME))
153  {
154  if(!CreateDir(SESSION_DIR_NAME))
155  {
156  DirOpenError = true;
157  }
158  }
159  if(!DirectoryExists(IMAGE_DIR_NAME))
160  {
161  if(!CreateDir(IMAGE_DIR_NAME))
162  {
163  DirOpenError = true;
164  }
165  }
166  if(!DirectoryExists(FORMATTEDTT_DIR_NAME))
167  {
168  if(!CreateDir(FORMATTEDTT_DIR_NAME))
169  {
170  DirOpenError = true;
171  }
172  }
173  if(!DirectoryExists(USERGRAPHICS_DIR_NAME))
174  {
175  if(!CreateDir(USERGRAPHICS_DIR_NAME))
176  {
177  DirOpenError = true;
178  }
179  }
180  if(DirOpenError)
181  {
182  ShowMessage("Failed to create one or more of folders: " + RAILWAY_DIR_NAME + ", " + TIMETABLE_DIR_NAME + ", " + PERFLOG_DIR_NAME + ", " +
184  "program operation will be restricted");
185  }
186  Application->HelpFile = AnsiString(CurDir + "\\Help.chm"); // added at v2.0.0 for .chm help file
187 
188  MainMenu1->AutoHotkeys = maManual; // Embarcadero mod: to suppress '&' inclusion for underlined characters in menu items
189  PopupMenu->AutoHotkeys = maManual; // as above
190 
191  Utilities = new TUtilities;
192  RailGraphics = new TRailGraphics();
193 
194  int DispW = (Screen->Width - 64) / 16; // will truncate down to a multiple of 16 OK here as screen dimensions are accurate
195  int DispH = (Screen->Height - 192) / 16; // Interface dimensions are 16 too wide & 14 short in height
196  MainScreen->Width = DispW * 16;
197  MainScreen->Height = DispH * 16;
198 
201  Utilities->ScreenElementWidth = DispW;
203  HiddenScreen = new TImage(Interface);
204  HiddenScreen->Width = MainScreen->Width;
205  HiddenScreen->Height = MainScreen->Height;
209  Track = new TTrack;
210  AllRoutes = new TAllRoutes;
216  SelectBitmap = new Graphics::TBitmap;
217  SelectBitmap->PixelFormat = pf8bit;
218  SelectBitmap->Transparent = true;
223  LengthWarningSentFlag = false;
224  PasteWarningSentFlag = false; // added at v2.6.0
225  FillSelectionMessageSentFlag = false; // added at v2.6.0
226  LCManualLowerBarriersMessageSent = false; // added at v2.6.0
227  RecoverClipboardMessageSent = false; // added at v2.8.0
228  TooLongMessageSentFlag = false; //added at v2.9.1
229  TooShortMessageSentFlag = false; //added at v2.9.1
230  Track->NoPlatsMessageSent = false; //added at v2.10.0
231  PrefDirConflictAdviceMessageSent = false; //added at v2.13.0
232  Track->DefaultTrackLength = 100; //moved here at v2.11.0, may be changed in reading config.txt
233  Track->DefaultTrackSpeedLimit = 200; //moved here at v2.11.0, may be changed in reading config.txt
234 
235 
236  TrackInfoOnOffMenuItem->Caption = "Show"; // added here at v1.2.0 because dropped from ResetAll()
237  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status"; // changed at v2.0.0 so normally visible
238  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable"; // as above
239 
240  /* ======================= ROS Dummy API ===============================
241  Connect API to track variables of interest, added at v2.10.0
242  */
243  session_api_ = new API(CurDir + "\\session.ini");
246  session_api_->add_metadata_str("performance_file", &PerformanceFileName);
248  session_api_->add_metadata_int("operation_mode", &api_oper_mode_);
249 
250  // =====================================================================
251 
252  ResetAll(0);
253 
254  TempTTFileName = "";
255 
260 
261  RouteFlashDuration = 0.0;
262  PointsFlashDuration = 0.0;
263 
264  FloatingLabel->Color = clB4G5R5;
265  TrackElementPanel->Color = clB5G5R4;
266  InfoPanel->Color = clB4G5R5;
267 
268  Utilities->RHSignalFlag = false; // new at v2.3.0 for RH signals, always left hand on startup
269  SigsOnLeftImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
270  SigsOnLeftImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
271  SigsOnLeftImage1->Transparent = true;
272  SigsOnLeftImage2->Transparent = true;
273  SigsOnLeftImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
274  SigsOnLeftImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
275  SigsOnRightImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
276  SigsOnRightImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
277  SigsOnRightImage1->Transparent = true;
278  SigsOnRightImage2->Transparent = true;
279  SigsOnRightImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
280  SigsOnRightImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
281 
282  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME; // default locations, may be changed when Config.txt loaded
283  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
284  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
285  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
286  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
287  LoadUserGraphicDialog->InitialDir = CurDir + "\\" + USERGRAPHICS_DIR_NAME; // not changeable
288  LoadCouplingFileDialog->InitialDir = CurDir; // not changeable
289 
290  ReloadConfigMenuItem->Enabled = true; //new at v2.11.0
291  LoadConfigFile(0, true); //true for first load
292 
293  SpeedButton1->Glyph->LoadFromResourceName(0, "gl1");
294  SpeedButton2->Glyph->LoadFromResourceName(0, "gl2");
295  SpeedButton3->Glyph->LoadFromResourceName(0, "gl3");
296  SpeedButton4->Glyph->LoadFromResourceName(0, "gl4");
297  SpeedButton5->Glyph->LoadFromResourceName(0, "gl5");
298  SpeedButton6->Glyph->LoadFromResourceName(0, "gl6");
299  SpeedButton7->Glyph->LoadFromResourceName(0, "gl7");
300  SpeedButton8->Glyph->LoadFromResourceName(0, "gl8");
301  SpeedButton9->Glyph->LoadFromResourceName(0, "gl9");
302  SpeedButton10->Glyph->LoadFromResourceName(0, "gl10");
303  SpeedButton11->Glyph->LoadFromResourceName(0, "gl11");
304  SpeedButton12->Glyph->LoadFromResourceName(0, "gl12");
305  SpeedButton13->Glyph->LoadFromResourceName(0, "gl13");
306  SpeedButton14->Glyph->LoadFromResourceName(0, "gl14");
307  SpeedButton15->Glyph->LoadFromResourceName(0, "gl15");
308  SpeedButton16->Glyph->LoadFromResourceName(0, "gl16");
309  SpeedButton18->Glyph->LoadFromResourceName(0, "gl18");
310  SpeedButton19->Glyph->LoadFromResourceName(0, "gl19");
311  SpeedButton20->Glyph->LoadFromResourceName(0, "gl20");
312  SpeedButton21->Glyph->LoadFromResourceName(0, "gl21");
313  SpeedButton22->Glyph->LoadFromResourceName(0, "gl22");
314  SpeedButton23->Glyph->LoadFromResourceName(0, "gl23");
315  SpeedButton24->Glyph->LoadFromResourceName(0, "gl24");
316  SpeedButton25->Glyph->LoadFromResourceName(0, "gl25");
317  SpeedButton26->Glyph->LoadFromResourceName(0, "gl26");
318  SpeedButton27->Glyph->LoadFromResourceName(0, "gl27");
319  SpeedButton28->Glyph->LoadFromResourceName(0, "gl28");
320  SpeedButton29->Glyph->LoadFromResourceName(0, "gl29");
321  SpeedButton30->Glyph->LoadFromResourceName(0, "gl30");
322  SpeedButton31->Glyph->LoadFromResourceName(0, "gl31");
323  SpeedButton32->Glyph->LoadFromResourceName(0, "gl32");
324  SpeedButton33->Glyph->LoadFromResourceName(0, "gl33");
325  SpeedButton34->Glyph->LoadFromResourceName(0, "gl34");
326  SpeedButton35->Glyph->LoadFromResourceName(0, "gl35");
327  SpeedButton36->Glyph->LoadFromResourceName(0, "gl36");
328  SpeedButton37->Glyph->LoadFromResourceName(0, "gl37");
329  SpeedButton38->Glyph->LoadFromResourceName(0, "gl38");
330  SpeedButton39->Glyph->LoadFromResourceName(0, "gl39");
331  SpeedButton40->Glyph->LoadFromResourceName(0, "gl40");
332  SpeedButton41->Glyph->LoadFromResourceName(0, "gl41");
333  SpeedButton42->Glyph->LoadFromResourceName(0, "gl42");
334  SpeedButton43->Glyph->LoadFromResourceName(0, "gl43");
335  SpeedButton44->Glyph->LoadFromResourceName(0, "gl44");
336  SpeedButton45->Glyph->LoadFromResourceName(0, "gl45");
337  SpeedButton46->Glyph->LoadFromResourceName(0, "gl46");
338  SpeedButton47->Glyph->LoadFromResourceName(0, "gl47");
339  SpeedButton48->Glyph->LoadFromResourceName(0, "gl48");
340  SpeedButton49->Glyph->LoadFromResourceName(0, "gl49");
341  SpeedButton50->Glyph->LoadFromResourceName(0, "gl50");
342  SpeedButton51->Glyph->LoadFromResourceName(0, "gl51");
343  SpeedButton52->Glyph->LoadFromResourceName(0, "gl52");
344  SpeedButton53->Glyph->LoadFromResourceName(0, "gl53");
345  SpeedButton54->Glyph->LoadFromResourceName(0, "gl54");
346  SpeedButton55->Glyph->LoadFromResourceName(0, "gl55");
347  SpeedButton56->Glyph->LoadFromResourceName(0, "gl56");
348  SpeedButton57->Glyph->LoadFromResourceName(0, "gl57");
349  SpeedButton58->Glyph->LoadFromResourceName(0, "gl58");
350  SpeedButton59->Glyph->LoadFromResourceName(0, "gl59");
351  SpeedButton60->Glyph->LoadFromResourceName(0, "gl60");
352  SpeedButton61->Glyph->LoadFromResourceName(0, "gl61");
353  SpeedButton62->Glyph->LoadFromResourceName(0, "gl62");
354  SpeedButton63->Glyph->LoadFromResourceName(0, "gl63");
355  SpeedButton64->Glyph->LoadFromResourceName(0, "gl64");
356  SpeedButton65->Glyph->LoadFromResourceName(0, "gl65");
357  SpeedButton66->Glyph->LoadFromResourceName(0, "gl66");
358  SpeedButton67->Glyph->LoadFromResourceName(0, "gl67");
359  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68");
360  SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
361  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70");
362  SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
363  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72");
364  SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
365  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74");
366  SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
367  SpeedButton76->Glyph->LoadFromResourceName(0, "gl76");
368  SpeedButton77->Glyph->LoadFromResourceName(0, "gl77");
369  SpeedButton78->Glyph->LoadFromResourceName(0, "gl78");
370  SpeedButton79->Glyph->LoadFromResourceName(0, "gl79");
371  SpeedButton80->Glyph->LoadFromResourceName(0, "gl80");
372  SpeedButton81->Glyph->LoadFromResourceName(0, "gl81");
373  SpeedButton82->Glyph->LoadFromResourceName(0, "gl82");
374  SpeedButton83->Glyph->LoadFromResourceName(0, "gl83");
375  SpeedButton84->Glyph->LoadFromResourceName(0, "gl84");
376  SpeedButton85->Glyph->LoadFromResourceName(0, "gl85");
377  SpeedButton86->Glyph->LoadFromResourceName(0, "gl86");
378  SpeedButton87->Glyph->LoadFromResourceName(0, "gl87");
379  SpeedButton88->Glyph->LoadFromResourceName(0, "gl88set");
380  SpeedButton89->Glyph->LoadFromResourceName(0, "gl89set");
381  SpeedButton90->Glyph->LoadFromResourceName(0, "gl90set");
382  SpeedButton91->Glyph->LoadFromResourceName(0, "gl91set");
383  SpeedButton92->Glyph->LoadFromResourceName(0, "gl92set");
384  SpeedButton93->Glyph->LoadFromResourceName(0, "gl93set");
385  SpeedButton94->Glyph->LoadFromResourceName(0, "gl94set");
386  SpeedButton95->Glyph->LoadFromResourceName(0, "gl95set");
387  SpeedButton96->Glyph->LoadFromResourceName(0, "ConcourseGlyph");
388  SpeedButton97->Glyph->LoadFromResourceName(0, "gl97");
389  SpeedButton98->Glyph->LoadFromResourceName(0, "gl98");
390  SpeedButton99->Glyph->LoadFromResourceName(0, "gl99");
391  SpeedButton100->Glyph->LoadFromResourceName(0, "gl100");
392  SpeedButton101->Glyph->LoadFromResourceName(0, "gl101");
393  SpeedButton102->Glyph->LoadFromResourceName(0, "gl102");
394  SpeedButton103->Glyph->LoadFromResourceName(0, "gl103");
395  SpeedButton104->Glyph->LoadFromResourceName(0, "gl104");
396  SpeedButton105->Glyph->LoadFromResourceName(0, "gl105");
397  SpeedButton106->Glyph->LoadFromResourceName(0, "gl106");
398  SpeedButton107->Glyph->LoadFromResourceName(0, "gl107");
399  SpeedButton108->Glyph->LoadFromResourceName(0, "gl108");
400  SpeedButton109->Glyph->LoadFromResourceName(0, "gl109");
401  SpeedButton110->Glyph->LoadFromResourceName(0, "gl110");
402  SpeedButton111->Glyph->LoadFromResourceName(0, "gl111");
403  SpeedButton112->Glyph->LoadFromResourceName(0, "gl112");
404  SpeedButton113->Glyph->LoadFromResourceName(0, "gl113");
405  SpeedButton114->Glyph->LoadFromResourceName(0, "gl114");
406  SpeedButton115->Glyph->LoadFromResourceName(0, "gl115");
407  SpeedButton116->Glyph->LoadFromResourceName(0, "gl116");
408  SpeedButton117->Glyph->LoadFromResourceName(0, "gl117");
409  SpeedButton118->Glyph->LoadFromResourceName(0, "gl118");
410  SpeedButton119->Glyph->LoadFromResourceName(0, "gl119");
411  SpeedButton120->Glyph->LoadFromResourceName(0, "gl120");
412  SpeedButton121->Glyph->LoadFromResourceName(0, "gl121");
413  SpeedButton122->Glyph->LoadFromResourceName(0, "gl122");
414  SpeedButton123->Glyph->LoadFromResourceName(0, "gl123");
415  SpeedButton124->Glyph->LoadFromResourceName(0, "gl124");
416  SpeedButton125->Glyph->LoadFromResourceName(0, "gl125");
417  SpeedButton126->Glyph->LoadFromResourceName(0, "gl126");
418  SpeedButton127->Glyph->LoadFromResourceName(0, "gl127");
419  SpeedButton128->Glyph->LoadFromResourceName(0, "gl128");
420  SpeedButton129->Glyph->LoadFromResourceName(0, "gl129");
421  SpeedButton130->Glyph->LoadFromResourceName(0, "gl130");
422  SpeedButton131->Glyph->LoadFromResourceName(0, "gl131");
423  SpeedButton132->Glyph->LoadFromResourceName(0, "gl132");
424  SpeedButton133->Glyph->LoadFromResourceName(0, "gl133");
425  SpeedButton134->Glyph->LoadFromResourceName(0, "gl134");
426  SpeedButton135->Glyph->LoadFromResourceName(0, "gl135");
427  SpeedButton136->Glyph->LoadFromResourceName(0, "gl136");
428  SpeedButton137->Glyph->LoadFromResourceName(0, "gl137");
429  SpeedButton138->Glyph->LoadFromResourceName(0, "gl138");
430  SpeedButton139->Glyph->LoadFromResourceName(0, "gl139");
431  SpeedButton140->Glyph->LoadFromResourceName(0, "gl140");
432  SpeedButton141->Glyph->LoadFromResourceName(0, "gl141");
433  SpeedButton142->Glyph->LoadFromResourceName(0, "gl142");
434  SpeedButton143->Glyph->LoadFromResourceName(0, "gl143");
435  SpeedButton145->Glyph->LoadFromResourceName(0, "gl145");
436  SpeedButton146->Glyph->LoadFromResourceName(0, "gl146");
437  // below not in RailGraphics
438  SpeedButton144->Glyph->LoadFromResourceName(0, "LCGlyph");
439 
440  AddPrefDirButton->Glyph->LoadFromResourceName(0, "AddPrefDir");
441  AddTextButton->Glyph->LoadFromResourceName(0, "AddText");
442  AddTrackButton->Glyph->LoadFromResourceName(0, "AddTrack");
443  AutoSigsButton->Glyph->LoadFromResourceName(0, "AutoSig");
444  CallingOnButton->Glyph->LoadFromResourceName(0, "CallingOn");
445  DeleteAllPrefDirButton->Glyph->LoadFromResourceName(0, "ClearAllPrefDir");
446  DeleteOnePrefDirButton->Glyph->LoadFromResourceName(0, "ClearOnePrefDir");
447  ExitOperationButton->Glyph->LoadFromResourceName(0, "Exit");
448  ExitPrefDirButton->Glyph->LoadFromResourceName(0, "Exit");
449  ExitTrackButton->Glyph->LoadFromResourceName(0, "Exit");
450  ExitTTModeButton->Glyph->LoadFromResourceName(0, "Exit");
451  FontButton->Glyph->LoadFromResourceName(0, "FontGraphic");
452  HomeButton->Glyph->LoadFromResourceName(0, "Home");
453  LocationNameButton->Glyph->LoadFromResourceName(0, "NameLocs");
454  MoveTextOrGraphicButton->Glyph->LoadFromResourceName(0, "MoveTextOrGraphic");
455  NewHomeButton->Glyph->LoadFromResourceName(0, "NewHome");
456  UnrestrictedButton->Glyph->LoadFromResourceName(0, "NonSig");
457  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
458  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
459  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
460  PresetAutoSigRoutesButton->Glyph->LoadFromResourceName(0, "PresetAutoSigRoutes");
461  RouteCancelButton->Glyph->LoadFromResourceName(0, "RouteCancel");
462  SaveRailwayPDPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // PrefDirPanel
463  SaveRailwayBaseModeButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // OperatingPanel
464  SaveRailwayTBPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // TrackBuildPanel
465  SaveSessionButton->Glyph->LoadFromResourceName(0, "SaveSession");
466  ScreenDownButton->Glyph->LoadFromResourceName(0, "BlackArrowDown");
467  ScreenGridButton->Glyph->LoadFromResourceName(0, "ScreenGrid");
468  ScreenLeftButton->Glyph->LoadFromResourceName(0, "BlackArrowLeft");
469  ScreenRightButton->Glyph->LoadFromResourceName(0, "BlackArrowRight");
470  ScreenUpButton->Glyph->LoadFromResourceName(0, "BlackArrowUp");
471  SetGapsButton->Glyph->LoadFromResourceName(0, "ConnectGaps");
472  SetLengthsButton->Glyph->LoadFromResourceName(0, "SetDists");
473  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
474  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect"); // new at version 0.6
475  SigPrefConsecButton->Glyph->LoadFromResourceName(0, "PrefTop");
476  SigPrefNonConsecButton->Glyph->LoadFromResourceName(0, "PrefBottom");
477  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
478  TrackOKButton->Glyph->LoadFromResourceName(0, "Validate");
479  TTClockAdjButton->Glyph->LoadFromResourceName(0, "TTClock");
480  UserGraphicButton->Glyph->LoadFromResourceName(0, "PictureImage");
481 
482  BufferAttentionImage->Picture->Bitmap->LoadFromResourceName(0, "BufferWarning");
483  CallOnImage->Picture->Bitmap->LoadFromResourceName(0, "CallingOn");
484  CrashImage->Picture->Bitmap->LoadFromResourceName(0, "CrashWarning");
485  DerailImage->Picture->Bitmap->LoadFromResourceName(0, "DerailWarning");
486  SignalStopImage->Picture->Bitmap->LoadFromResourceName(0, "SignalStopWarning");
487  SPADImage->Picture->Bitmap->LoadFromResourceName(0, "SPADWarning");
488  TrainFailedImage->Picture->Bitmap->LoadFromResourceName(0, "TrainFailedWarning"); // new at v2.4.0
489  ManualLCDownImage->Picture->Bitmap->LoadFromResourceName(0, "ManualLCDownImage"); // new at v2.9.0
490 
491  DistanceKey->Picture->Bitmap->LoadFromResourceName(0, "DistanceKey");
492  PrefDirKey->Picture->Bitmap->LoadFromResourceName(0, "PrefDirKey");
493 
494  TrackLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackLinkedGraphic");
495  TrackNotLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackNotLinkedGraphic");
496  GapsNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsNotSetGraphic");
497  GapsSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsSetGraphic");
498  LocationNamesNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesNotSetGraphic");
499  LocationNamesSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesSetGraphic");
500 
501  SkipListExitImage->Picture->Bitmap->LoadFromResourceName(0, "Exit"); //new at v2.11.0
502 
503 
504 /* Don't need this - load icon directly into both Interface form & Application (via Project - Options - Application - Load Icon)
505  RailwayIcon = new TPicture;
506  RailwayIcon->Icon->LoadFromResourceName(0, "Icon1.ico");
507  Icon = RailwayIcon->Icon;
508  Application->Icon = RailwayIcon->Icon;
509 */
510 
511  AnsiString NL = '\n';
512  const AnsiString TTLabelStr1 = "Start new train" + NL + "Start new service from a split" + NL + "Start new service from another service" + NL +
513  "Start new non-repeating shuttle finish service" + NL + "Start new shuttle train at a timetabled stop" + NL +
514  "Start new shuttle service from a feeder";
515 
516  const AnsiString TTLabelStr2 = "Pass" + NL + "Be joined by another train" + NL + "Front split" + NL + "Rear split" + NL + "Change direction of train";
517 
518  const AnsiString TTLabelStr3 = "Finish && form a new service" + NL + "Finish && join another train" + NL + "Finish && exit railway" + NL +
519  "Finish && repeat shuttle, finally remain here" + NL + "Finish && repeat shuttle, finally form a finishing service" + NL +
520  "Finish non-repeating shuttle feeder service" + NL + "Finish && remain here";
521 
522  const AnsiString TTLabelStr4 = "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL +
523  "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + " " +
524  NL + "R";
525 
526  const AnsiString TTLabelStr5 = "HH:MM ';' Location" + NL + "HH:MM ';' HH:MM ';' Location";
527 
528  const AnsiString TTLabelStr6 = "+ rear element ID - space - front element ID [+ optional ';S']" + NL + "+ ref. of the train that splits" + NL +
529  "+ other service ref." + NL + "+ shuttle service ref." + NL + "+ rear element ID - space - front element ID ';' linked shuttle ref." + NL +
530  "+ linked shuttle service ref. ';' feeder service ref." + NL + "+ location" + NL + "+ joining train ref." + NL + "+ new service ref." + NL +
531  "+ new service ref." + NL + " " + NL + "+ new service ref." + NL + "+ ref. of train to join" + NL +
532  "+ list of valid exit element IDs (at least 1) separated by spaces" + NL + "+ linked shuttle service ref.";
533 
534  const AnsiString TTLabelStr7 = "Arrival OR departure time (program will determine which from the context) + location." + NL +
535  "Arrival time, departure time (with no events between) + location";
536 
537  const AnsiString TTLabelStr9 = "Timetable entries" + NL + "(service references etc.)";
538  const AnsiString TTLabelStr11 = "Timetable" + NL + "start time";
539 
540  const AnsiString TTLabelStr12 = "NB: WITHIN SERVICES commas must" + NL + "not be used (have special meanings)," + NL +
541  "and semicolons may only be used to" + NL + "separate service components.";
542 
543  const AnsiString TTLabelStr13 = "+ linked shuttle service ref. ';' finishing service ref." + NL + "+ linked shuttle service ref.";
544 
545  const AnsiString TTLabelStr15 = "Repeat the service + ';' minutes between repeats ';' digit increment ';' number of repeats (last line of service)";
546 
547  TTLabel1->Caption = TTLabelStr1;
548  TTLabel2->Caption = TTLabelStr2;
549  TTLabel3->Caption = TTLabelStr3;
550  TTLabel4->Caption = TTLabelStr4;
551  TTLabel5->Caption = TTLabelStr5;
552  TTLabel6->Caption = TTLabelStr6;
553  TTLabel7->Caption = TTLabelStr7;
554  TTLabel9->Caption = TTLabelStr9;
555  TTLabel11->Caption = TTLabelStr11;
556  TTLabel12->Caption = TTLabelStr12;
557  TTLabel13->Caption = TTLabelStr13;
558  TTLabel15->Caption = TTLabelStr15;
559 
560  SelectBitmap->TransparentColor = Utilities->clTransparent;
561  RailGraphics->ChangeAllTransparentColours(Utilities->clTransparent, clB5G5R5); // original colour is as loaded at this stage - white
563 
564  TextBox->Color = clB3G3R3;
565  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
566  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
567 
568  if((Screen->Width < 1024) || (Screen->Height < 768))
569  {
570  ShowMessage("Please note that this program works best with a screen resolution of at least 1024 x 768. Please change if possible");
571  }
572  SkipFormResizeEvent = true; // added at v2.1.0
573  MasterClock->Enabled = true;
574  Visible = true; // make Interface form visible (set to false at design time) autocalls FormResize so it is skipped by SkipFormResizeEvent being true
575  WindowState = wsMaximized; // need this for full screen at start autocalls FormResize so it is skipped by SkipFormResizeEvent being true
576  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30; // new v2.4.0 30 is to place it above the positional panel
577  // has to come after Visible = true or doesn't show
578  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
579  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
580  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
581  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
582  AllSetUpFlag = true;
583  TotalTicks = 0;
585  SetLevel1Mode(131); // to reset background colour mode menu choices
586  Screen->Cursor = TCursor(-2); // Arrow
587  SkipFormResizeEvent = false; // added at v2.1.0
588  SelectedGraphicFileName = ""; // only set to null here so always has a value after use LoadUserGraphic
589 
590  FloatingPanel->Color = TColor(0xF0FFFF); // new v2.2.0, corrects floating panel background colour in Windows 10
591  PerformancePanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
592  OperatorActionPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
593  DevelopmentPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
594  TTStartTimeBox->Color = TColor(0x99FFFF); // cream
595  HighlightPanel->Color = TColor(0x33CCFF);
597  MTBFEditBox->Visible = false; // new at v2.4.0
598  MTBFLabel->Visible = false;
602  CancelSelectionFlag = false;
603  TTStartTimePtr = 0;
604  TTFirstServicePtr = 0;
605  TTLastServicePtr = 0;
606  Track->OverrideAndHideSignalBridgeMessage = false; // added at v2.5.1 to allow facing signals before bridges - with a warning
607  ConflictPanel->Visible = false;
608  TTClockAdjustWarningPanel->Visible = false;
609  TTClockAdjustWarningHide = false;
610  TwoLocationNamePanel->Visible = false;
611  TwoLocationNamePanelHide = false;
612  LastNonCtrlOrShiftKeyDown = -1; // set to no key
613  ClipboardChecked = false;
614  MMoveTrackSelFlag = false;
615  MMovePrefDirSelFlag = false;
619  NumPlayers = 0; //Multiplayer integer
620  MultiplayerMenu->Enabled = false;
621  MultiplayerMenu->Visible = false; //<-- only until multiplayer added (also temproarily false in designer)
622  CouplingFileLoadedFlag = false;
624  PlayerReadyToBeginFlag = false;
625  PlayerCancelJoinFlag = false;
627  HostInSessionFlag = false;
628  PlayerInSessionFlag = false;
629  LastHostDataReceived = TDateTime(0);//initial value
631  SkipTTActionsListBox->Visible = false;
632  SkipListHeaderPanel->Visible = false;
634  ElapsedTimerRunning = false;
636  NoDelaysMenuItem->Enabled = false;
637  Utilities->CumulativeDelayedRandMinsAllTrains = 0; //added at v2.13.0
638  AllEntriesTTListBox->TopIndex = 0; //added at v2.13.0 to initialise the value (seemed to initialise to 0 without this but not documented)
639 
640  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
641 
642  // below added at v2.4.0 so able to load session files with the correct decimal point
643  Utilities->DecimalPoint = '.'; // default case is full stop
644  char *LocalNumericInformation = setlocale(LC_NUMERIC, ""); // need this to set lconv to the environment's numeric format
646  if(LocalNumericInformation == "") // call failed, don't change decimal point in Utilities.cpp
647  {
648  Utilities->SetLocaleResultOK = false;
649  }
650  struct lconv Locale; // store this structure in memory (accessed via locale.h in Utilities.h)
651  struct lconv *conv = &Locale;
652  // read the locality conversion structure
653  conv = localeconv(); // this is what updates the structure
654  Utilities->DecimalPoint = conv->decimal_point[0];
655  }
656 
657  catch(const EFOpenError &e)
658  {
659  TMsgDlgButtons But;
660  But << mbOK;
661  MessageDlg(e.Message + " - program must terminate", mtError, But, 0);
662  Application->Terminate();
663  }
664 
665  catch(const Exception &e)
666  {
667  TMsgDlgButtons But;
668  But << mbOK;
669  AnsiString Message = "A fatal error occurred during the program setup process, the program must terminate. Message = " + e.Message;
670  MessageDlg(Message, mtError, But, 0); // this message given first in case can't create the error log
671  ErrorLog(115, e.Message);
672  Application->Terminate();
673  }
674 }
675 
676 // ---------------------------------------------------------------------------
677 
679 {
680  // destructor
681  try
682  {
683  // rewrite ConfigFile with signal handedness, background colour, InitialDir values (may be same but no matter) & default track element length & speed limit
684  SaveConfigFile(0); //added at v2.11.0
685  DeleteFile(TempTTFileName); // added at v2.5.0 to prevent temporary files building up
686  SkipFormResizeEvent = true; // added at v2.1.0
687  delete NonSigRouteStartMarker;
688  delete SigRouteStartMarker;
689  delete AutoRouteStartMarker;
690  delete PointFlash;
691  delete SelectBitmap;
692  delete TrainController;
693  delete EveryPrefDir;
694  delete SelectPrefDir;
695  delete ConstructRoute;
696  delete ConstructPrefDir;
697  delete AllRoutes;
698  delete Track;
699  delete TextHandler;
700  delete HiddenDisplay;
701  delete HiddenScreen;
702  delete Display;
703  delete RailGraphics;
704  delete Utilities;
705  delete session_api_; //added at v2.10.0
706  }
707  catch(const Exception &e)
708  {
709  ErrorLog(116, e.Message);
710  }
711 }
713 
714 // ---------------------------------------------------------------------------
715 
716 void __fastcall TInterface::FormCreate(TObject *Sender)
717 {
718  // these functions have to be defined here to take effect when application activated & deactivated
719  try
720  {
721  Application->OnDeactivate = AppDeactivate;
722  Application->OnActivate = AppActivate;
723  }
724  catch(const Exception &e)
725  {
726  ErrorLog(117, e.Message);
727  }
728 }
729 
730 // ---------------------------------------------------------------------------
731 
732 void __fastcall TInterface::AppDeactivate(TObject *Sender)
733 {
734  // pause operation if operating & stop the master clock
735  try
736  {
738  {
739  if(Track->RouteFlashFlag) // in case route building - cancels the route, freezes otherwise - reported
740  {
741  // by Matt Blades 30/06/11
745  Screen->Cursor = TCursor(-2); // Arrow
746  Track->RouteFlashFlag = false;
747  ClearandRebuildRailway(48); // to get rid of displayed route
748  }
749  if(Track->PointFlashFlag)
750  // added at v1.3.1 to prevent lockup for flashing points when deactivates. Notified by Ian Walker in his email of 25/03/13.
751  {
753  Track->PointFlashFlag = false;
755  Screen->Cursor = TCursor(-2); // Arrow
756  }
757  if(!HostInSessionFlag && !PlayerInSessionFlag) //don't pause if multiplay in session
758  {
761  }
762  }
764  {
765  MasterClock->Enabled = false; //keep enabled for comms in multiplayer
766  }
767  ClipboardChecked = false; // added at v2.8.0 to force a check of the clipboard (via ClockTimer2 & SetTrackModeMenu)
768  }
769  catch(const Exception &e)
770  {
771  ErrorLog(118, e.Message);
772  }
773 }
774 
775 // ---------------------------------------------------------------------------
776 
777 void __fastcall TInterface::AppActivate(TObject *Sender)
778 {
779  // restart the master clock providing Interface constructor has run
780  try
781  {
782  if(AllSetUpFlag)
783  {
784  MasterClock->Enabled = true; //will already be enabled if no multiplay
785  ClipboardChecked = false; // at v2.9.0 added here too as for some unknown reason it doesn't always work when just in deactivate
786  }
787  }
788  catch(const Exception &e)
789  {
790  ErrorLog(119, e.Message);
791  }
792 }
793 
794 // ---------------------------------------------------------------------------
795 
796 UnicodeString TInterface::GetVersion()
797 {
798  DWORD VersionHandle;
799  DWORD VersionSize;
800  LPBYTE pBuffer;
801  UnicodeString strVersion = L"N/A";
802 
803  VersionSize = GetFileVersionInfoSizeW(Application->ExeName.c_str(), &VersionHandle);
804  if(VersionSize)
805  {
806  pBuffer = new BYTE[VersionSize];
807 
808  if(GetFileVersionInfoW(Application->ExeName.c_str(), VersionHandle, VersionSize, pBuffer))
809  {
810  VS_FIXEDFILEINFO *fi;
811  UINT buflen;
812 
813  // uncomment strVersion and HIWORD alternates below when future CI implemented: sas@2.1.0
814  if(VerQueryValueW(pBuffer, L"\\", (void**)&fi, &buflen))
815  {
816  // strVersion.sprintf(L"%d.%d.%d (Build %d)",
817  strVersion.sprintf(L"%d.%d.%d", HIWORD(fi->dwFileVersionMS), LOWORD(fi->dwFileVersionMS), HIWORD(fi->dwFileVersionLS));
818  // HIWORD(fi->dwFileVersionLS), LOWORD(fi->dwFileVersionLS)
819  }
820  }
821  delete[]pBuffer;
822  }
823  return(L" v" + strVersion);
824 }
825 
826 // ---------------------------------------------------------------------------
827 // Track Build Interface
828 // ---------------------------------------------------------------------------
829 void __fastcall TInterface::BuildTrackMenuItemClick(TObject *Sender) // Mode Menu Item
830 {
831  try
832  {
833  TrainController->LogEvent("BuildTrackMenuItemClick");
834  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildTrackMenuItemClick");
836  SetLevel1Mode(0);
837  Utilities->CallLogPop(1159);
838  }
839  catch(const Exception &e)
840  {
841  ErrorLog(120, e.Message);
842  }
843 }
844 // ---------------------------------------------------------------------------
845 
846 void __fastcall TInterface::AddTrackButtonClick(TObject *Sender)
847 {
848  try
849  {
850  TrainController->LogEvent("AddTrackButtonClick");
851  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTrackButtonClick");
853  SetLevel1Mode(38);
856  Utilities->CallLogPop(1162);
857  }
858  catch(const Exception &e)
859  {
860  ErrorLog(121, e.Message);
861  }
862 }
863 
864 // ---------------------------------------------------------------------------
865 void __fastcall TInterface::SpeedButtonClick(TObject *Sender)
866 {
867  try
868  {
869  TrainController->LogEvent("SpeedButtonClick");
870  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedButtonClick");
871  ReselectMenuItem->Enabled = false;
872  if(((TSpeedButton*)Sender)->Down)
873  {
874  CurrentSpeedButton = (TSpeedButton*)Sender;
875 // TrainController->LogEvent("SpeedButtonClick, " + CurrentSpeedButton->Tag); //v 1.3.1 - using non-AnsiString CurrentSpeedButton->Tag sends (for an unknown reason) a completely wrong string to LogEvent, usually "...(behind this message)"
876  TrainController->LogEvent("SpeedButtonClick, " + AnsiString(CurrentSpeedButton->Tag)); // new version //use for v1.3.2
877  if((Level2TrackMode == TrackSelecting) && (CurrentSpeedButton->Tag != 144))
878  // new addition at v2.6.0 to fill selected area with the element corresponding to CurrentSpeedButton
879  {
880  // 144 = level crossing & these not permitted
881  if((SelectRect.left != SelectRect.right) && (SelectRect.top != SelectRect.bottom) && SelectionValid)
882  {
883  Screen->Cursor = TCursor(-11); // Hourglass;
884  InfoPanel->Caption = "SELECTING: Filling area with chosen element";
885  bool FillSelectionFlag = false;
887  {
888  UnicodeString MessageStr =
889  "Click 'Yes' to fill the area with the chosen element or 'No' to abort.\n" "Existing elements won't be overwritten although track can\n"
890  "have platforms and non-station named location elements added.\n\nThis message will not be shown again.";
891  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
892  if(button == IDYES)
893  {
894  FillSelectionFlag = true;
895  }
896  }
897  if(FillSelectionFlag || FillSelectionMessageSentFlag)
898  {
899  bool TrackLinkingRequiredFlag = true;
900  for(int HLoc = SelectRect.left; HLoc < SelectRect.right; HLoc++)
901  {
902  for(int VLoc = SelectRect.top; VLoc < SelectRect.bottom; VLoc++)
903  {
904  if((HLoc != SelectRect.right) || (VLoc != SelectRect.bottom))
905  {
906  Track->PlotAndAddTrackElement(3, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, false);
907 // false for internal checks
908  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
909  }
910  else
911  {
912  Track->PlotAndAddTrackElement(4, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, true);
913 // internal checks true for last plot
914  }
915  }
916  }
917  }
918  Track->SetTrackFinished(false);
919  ClearandRebuildRailway(80); // to remove selection outline
920  SelectionValid = false;
921  Track->CopyFlag = false;
923  ResetSelectRect();
924  SetLevel1Mode(139);
926  SetLevel2TrackMode(66);
928  Screen->Cursor = TCursor(-2); // Arrow
929  ReselectMenuItem->Enabled = true; // allow when filling areas
930  }
931  }
932  }
933  else
934  {
935  CurrentSpeedButton = 0;
936  }
937  Utilities->CallLogPop(1163);
938  }
939  catch(const Exception &e)
940  {
941  ErrorLog(122, e.Message);
942  }
943 }
944 
945 // ---------------------------------------------------------------------------
946 void __fastcall TInterface::TrackOKButtonClick(TObject *Sender)
947 {
948  try
949  {
950  TrainController->LogEvent("TrackOKButtonClick");
951  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackOKButtonClick");
952  Screen->Cursor = TCursor(-11); // Hourglass; //added at v2.11.1
953  SelectionValid = false;
955  bool LocError;
956  int HLoc, VLoc;
957  // erase any corrupted PrefDirs then rebuild track & PrefDir vectors
958 // EveryPrefDir->EraseCorruptedElementsAfterTrackBuild(); not needed after dispensed with blank track elements for erased elements
959  if(!(Track->TryToConnectTrack(0, LocError, HLoc, VLoc, true))) // true for give messages
960  // if successful repositions TrackVector & builds TrackMap
961  {
962  if(LocError) // links not complete or other error - show offending element
963  {
964  while((Display->DisplayOffsetH - HLoc) > 0)
965  {
966  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
967  }
968  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
969  {
971  }
972  while((Display->DisplayOffsetV - VLoc) > 0)
973  {
974  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
975  }
976  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
977  {
979  }
981  Display->InvertElement(0, HLoc * 16, VLoc * 16);
982  ShowMessage("Incomplete track or other error - see highlighted element (it may be behind this message "
983  "which can be moved by left clicking the mouse in the title bar and dragging it).");
984  ClearandRebuildRailway(1); // to clear inversion
986  SetLevel1Mode(39);
987  Level2TrackMode = AddTrack; // go to add track regardless of where started from
989  Screen->Cursor = TCursor(-2); // Arrow //added at v2.11.1
990  Utilities->CallLogPop(0);
991  return;
992  }
993  else
994  {
995  // reach here if there are no track elements
996  ShowMessage("Unable to set any track links");
998  SetLevel1Mode(40);
1000  SetLevel2TrackMode(4); // go to add track regardless of where started from
1001  Screen->Cursor = TCursor(-2); // Arrow //added at v2.11.1
1002  Utilities->CallLogPop(1);
1003  return;
1004  }
1005  }
1006  else
1007  {
1008  // success so far as track is concerned ('TrackFinished' set in TryToConnectTrack)
1009  EveryPrefDir->RebuildPrefDirVector(0); // from TrackMap
1010  }
1011 // success if reach here ('TrackFinished' set in TryToConnectTrack)
1012  if(Level2TrackMode == AddTrack)
1013  {
1016  SetLevel1Mode(41);
1017  SetLevel2TrackMode(5);
1018  }
1019  else
1020  {
1022  SetLevel1Mode(36); // back to TrackMode if not in AddTrack mode
1023  }
1024  ShowMessage("Successful Completion");
1025  Screen->Cursor = TCursor(-2); // Arrow //added at v2.11.1
1026  Utilities->CallLogPop(2);
1027  }
1028  catch(const Exception &e)
1029  {
1030  ErrorLog(3, e.Message);
1031  }
1032 }
1033 
1034 // ---------------------------------------------------------------------------
1035 void __fastcall TInterface::SetGapsButtonClick(TObject *Sender)
1036 {
1037  try
1038  {
1039  TrainController->LogEvent("SetGapsButtonClick");
1040  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetGapsButtonClick");
1041  SelectionValid = false;
1042  ReselectMenuItem->Enabled = false;
1044  SetLevel1Mode(42);
1046  SetLevel2TrackMode(6);
1047  Utilities->CallLogPop(1164);
1048  }
1049  catch(const Exception &e)
1050  {
1051  ErrorLog(123, e.Message);
1052  }
1053 }
1054 
1055 // ---------------------------------------------------------------------------
1056 void __fastcall TInterface::AddTextButtonClick(TObject *Sender)
1057 {
1058  try
1059  {
1060  TrainController->LogEvent("AddTextButtonClick");
1061  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTextButtonClick");
1063  SetLevel1Mode(43);
1065  SetLevel2TrackMode(7);
1066  Utilities->CallLogPop(1165);
1067  }
1068  catch(const Exception &e)
1069  {
1070  ErrorLog(124, e.Message);
1071  }
1072 }
1073 
1074 // ---------------------------------------------------------------------------
1075 void __fastcall TInterface::MoveTextOrGraphicButtonClick(TObject *Sender)
1076 {
1077  try
1078  {
1079  TrainController->LogEvent("MoveTextOrGraphicButtonClick");
1080  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTextOrGraphicButtonClick");
1082  SetLevel1Mode(44);
1084  SetLevel2TrackMode(8);
1085  Utilities->CallLogPop(1166);
1086  }
1087  catch(const Exception &e)
1088  {
1089  ErrorLog(125, e.Message);
1090  }
1091 }
1092 
1093 // ---------------------------------------------------------------------------
1094 void __fastcall TInterface::TextBoxKeyPress(TObject *Sender, char &Key)
1095 {
1096  try
1097  {
1098  TrainController->LogEvent("TextBoxKeyPress," + AnsiString(Key));
1099  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextBoxKeyPress," + AnsiString(Key));
1100  if(Key == '\x0D') // CR
1101  {
1102  if(TextBox->Text != "") // if blank then don't save
1103  {
1104  if(Display->GetFont()->Color == clB5G5R5) // white
1105  {
1106  TFont *TempFont = new TFont;
1107  TempFont->Assign(Display->GetFont());
1108  TempFont->Color = clB0G0R0; // change to black for vector & saving
1109  Display->SetFont(TempFont);
1110  delete TempFont;
1111  }
1112  TFont *DisplayFont = Display->GetFont();
1113  TTextItem TempText = TTextItem(Text_X, Text_Y, TextBox->Text, DisplayFont);
1114  TempText.Font = DisplayFont; // may have been changed in above constructor when returned as reference
1116  ResetChangedFileDataAndCaption(12, true); // moved here from MainScreenMouseDown2 after 2.7.0 in case nothing changed
1117  }
1118  EditMenu->Enabled = true;
1119  TextBox->Visible = false;
1120  SetLevel2TrackMode(56); // to enable 'move text' if first text item added
1121  }
1122  else if(Key == '\x1B') // escape
1123  {
1124  if(TextBox->Text != "")
1125  {
1126  ResetChangedFileDataAndCaption(28, true); // added here after 2.7.0 in case replaced existing text (which is selected) with blank
1127  }
1128  TextBox->Visible = false;
1129  }
1130  Utilities->CallLogPop(3);
1131  }
1132  catch(const Exception &e)
1133  {
1134  ErrorLog(4, e.Message);
1135  }
1136 }
1137 
1138 // ---------------------------------------------------------------------------
1139 void __fastcall TInterface::LocationNameButtonClick(TObject *Sender)
1140 {
1141  try
1142  {
1143  TrainController->LogEvent("LocationNameButtonClick");
1144  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameButtonClick");
1146  SetLevel1Mode(45);
1148  SetLevel2TrackMode(9);
1149  Utilities->CallLogPop(1167);
1150  }
1151  catch(const Exception &e)
1152  {
1153  ErrorLog(126, e.Message);
1154  }
1155 }
1156 
1157 // ---------------------------------------------------------------------------
1158 void __fastcall TInterface::LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
1159 {
1160  try
1161  {
1162  TrainController->LogEvent("LocationNameKeyUp," + AnsiString(Key));
1163  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameKeyUp," + AnsiString(Key));
1164  if(Track->LNPendingList.empty())
1165  {
1166  ShowMessage("Error, location name being entered without an entry in LNPendingList");
1168  SetLevel1Mode(46);
1170  SetLevel2TrackMode(10);
1171  Utilities->CallLogPop(4);
1172  return;
1173  }
1174  if(Key == '\x1B') // escape
1175  {
1176  Track->LNPendingList.clear(); // get rid of existing entry
1178  SetLevel1Mode(47);
1180  SetLevel2TrackMode(11);
1181  Utilities->CallLogPop(5);
1182  return;
1183  }
1184  if(Key == '\x0D')
1185  {
1186  Screen->Cursor = TCursor(-11); // Hourglass;
1188  ResetChangedFileDataAndCaption(8, true); // moved here after 2.7.0 from mainScreenMouseDown2 in case nothing changed
1189  AnsiString ExistingName;
1190  LocationNameTextBox->Text = LocationNameTextBox->Text.Trim();
1191 // added at v2.6.1 to prevent added spaces because they skip the different location same name chack
1192  if(Track->LNPendingList.front() > -1)
1193  {
1194  ExistingName = Track->InactiveTrackElementAt(27, Track->LNPendingList.front()).LocationName;
1195  }
1196  else
1197  {
1198  ExistingName = Track->TrackElementAt(425, -1 - (Track->LNPendingList.front())).LocationName;
1199  }
1200  if(Track->LocationNameAllocated(1, LocationNameTextBox->Text) && (ExistingName != LocationNameTextBox->Text))
1201  {
1202  // name allocated to a different location
1203  UnicodeString MessageStr = UnicodeString("Another location named '") + LocationNameTextBox->Text +
1204  UnicodeString("' already exists. If you continue its name will be erased. Do you wish to continue?");
1205  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
1206  if(button == IDNO)
1207  {
1208  Track->LNPendingList.clear(); // get rid of existing entry
1209  Screen->Cursor = TCursor(-2); // Arrow
1211  SetLevel1Mode(48);
1213  SetLevel2TrackMode(12);
1214  Utilities->CallLogPop(6);
1215  return;
1216  }
1218  Track->EnterLocationName(1, LocationNameTextBox->Text, false);
1219  int HPos, VPos;
1220  bool UseExistingPosition = false;
1221  if(EraseLocationNameText(0, LocationNameTextBox->Text, HPos, VPos))
1222  {
1223  ;
1224  } // condition not used
1225 
1226  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1227  // but, the location to be named may also have an existing name, in which case that needs to be erased
1228  // and the position re-used
1229  if(ExistingName != "")
1230  {
1231  if(EraseLocationNameText(3, ExistingName, HPos, VPos))
1232  {
1233  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1234  }
1235  }
1236  AddLocationNameText(0, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1237  Screen->Cursor = TCursor(-2); // Arrow
1239  SetLevel1Mode(49);
1241  SetLevel2TrackMode(13);
1242  Utilities->CallLogPop(7);
1243  return;
1244  }
1245  else if(Track->LocationNameAllocated(2, LocationNameTextBox->Text) && (ExistingName == LocationNameTextBox->Text))
1246  {
1247  // same name being entered again
1248  Track->LNPendingList.clear(); // get rid of existing entry as the location already has this name
1249  // but in case the name is not already in text vector erase it and re-add it
1250  // if it wasn't in the vector erasing it has no effect
1251  int HPos, VPos;
1252  bool UseExistingPosition = false;
1253  if(EraseLocationNameText(2, LocationNameTextBox->Text, HPos, VPos))
1254  {
1255  UseExistingPosition = true;
1256  }
1257  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1258  AddLocationNameText(2, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1259  Screen->Cursor = TCursor(-2); // Arrow
1261  SetLevel1Mode(50);
1263  SetLevel2TrackMode(14);
1264  Utilities->CallLogPop(8);
1265  return;
1266  }
1267  else
1268  {
1269  // either a new name for an unnamed location, or a different name for a named location
1270  // check validity of entry
1271  AnsiString LocStr = LocationNameTextBox->Text;
1272  LocStr = LocStr.Trim(); // strip leading & trailing spaces, and control characters
1273  LocationNameTextBox->Text = LocStr; // reset this as used below
1274 /* drop this, now covered by ...Trim() above
1275  //strip leading spaces
1276  while((LocStr != "") && (LocStr[1] == ' '))
1277  {
1278  LocStr = LocStr.SubString(2, LocStr.Length()-1);
1279  }
1280 */
1281  if((LocStr != "") && (LocStr[1] >= '0') && (LocStr[1] <= '9')) // can't begin with a number
1282  {
1283  Screen->Cursor = TCursor(-2); // Arrow
1284  ShowMessage("Location name can't begin with a number");
1286  SetLevel1Mode(51);
1288  SetLevel2TrackMode(15);
1289  Utilities->CallLogPop(776);
1290  return;
1291  }
1292  if(LocStr.Length() > 50)
1293  {
1294  Screen->Cursor = TCursor(-2); // Arrow
1295  ShowMessage("Location name too long, 50 characters maximum");
1297  SetLevel1Mode(122);
1299  SetLevel2TrackMode(55);
1300  Utilities->CallLogPop(1735);
1301  return;
1302  }
1303  for(int x = 1; x <= LocStr.Length(); x++)
1304  {
1305  char Ch = LocStr[x];
1306  if((Ch != ' ') && (Ch != '&') && (Ch != '(') && (Ch != ')') && (Ch != ':') && (Ch != 39) && (Ch != '.') && (Ch != '-') && (Ch != '+') &&
1307  (Ch != '/') && ((Ch < '0') || (Ch > '9')) && ((Ch < 'A') || (Ch > 'Z')) && ((Ch < 'a') || (Ch > 'z')))
1308  {
1309  Screen->Cursor = TCursor(-2); // Arrow
1310  ShowMessage(
1311  "Location name contains one or more invalid characters, must be alphanumeric, brackets, space, full stop, colon, inverted comma, '-', '+', '/' or '&&'");
1313  SetLevel1Mode(52);
1315  SetLevel2TrackMode(16);
1316  Utilities->CallLogPop(777);
1317  return;
1318  }
1319  }
1320  if(LocStr == "cdt") // this has Time:Command which could be confused with Time:Loc
1321  {
1322  Screen->Cursor = TCursor(-2); // Arrow
1323  ShowMessage("Location name cannot be 'cdt', this name would interfere with the timetable");
1325  SetLevel1Mode(53);
1327  SetLevel2TrackMode(17);
1328  Utilities->CallLogPop(778);
1329  return;
1330  }
1331  Track->EnterLocationName(2, LocStr, false);
1332  // need to check if the location already has a name, and if so erase it from the textvector
1333  int HPos, VPos;
1334  bool UseExistingPosition = false;
1335  if(ExistingName != "")
1336  {
1337  if(EraseLocationNameText(1, ExistingName, HPos, VPos))
1338  {
1339  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1340  }
1341  }
1342  AddLocationNameText(1, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1343  Screen->Cursor = TCursor(-2); // Arrow
1345  SetLevel1Mode(54);
1347  SetLevel2TrackMode(18);
1348  Utilities->CallLogPop(9);
1349  return;
1350  }
1351  }
1352  Screen->Cursor = TCursor(-2); // Arrow
1353  Utilities->CallLogPop(10);
1354  }
1355  catch(const Exception &e)
1356  {
1357  ErrorLog(5, e.Message);
1358  }
1359 }
1360 
1361 // ---------------------------------------------------------------------------
1362 void __fastcall TInterface::SetLengthsButtonClick(TObject *Sender)
1363 {
1364  try
1365  {
1366  TrainController->LogEvent("SetLengthsButtonClick");
1367  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetLengthsButtonClick");
1368  SelectLengthsFlag = false;
1369  ConstructPrefDir->ExternalClearPrefDirAnd4MultiMap(); // added for extended distances
1371  SetLevel1Mode(55);
1373  SetLevel2TrackMode(19);
1374  Utilities->CallLogPop(1168);
1375  }
1376  catch(const Exception &e)
1377  {
1378  ErrorLog(127, e.Message);
1379  }
1380 }
1381 
1382 // ---------------------------------------------------------------------------
1383 void __fastcall TInterface::LengthOKButtonClick(TObject *Sender)
1384 {
1385  try
1386  {
1387  TrainController->LogEvent("LengthOKButtonClick," + DistanceBox->Text + "," + SpeedLimitBox->Text);
1388  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthOKButtonClick");
1389  ResetChangedFileDataAndCaption(4, true); // moved here after 2.7.0 so only need to save if something changed
1390  int Dist = 0, SpeedLimit = 0;
1391  AnsiString DistanceStr = DistanceBox->Text;
1392  if(SelectLengthsFlag && (DistanceStr == ""))
1393  {
1394  DistanceStr = "No change";
1395  }
1396  AnsiString SpeedStr = SpeedLimitBox->Text;
1397  if(SelectLengthsFlag && (SpeedStr == ""))
1398  {
1399  SpeedStr = "No change";
1400  }
1401  if(SelectLengthsFlag)
1402  {
1403  if(DistanceStr == "No change")
1404  {
1405  Dist = -1; // i.e.don't change
1406  }
1407  if(SpeedStr == "No change")
1408  {
1409  SpeedLimit = -1; // i.e.don't change
1410  }
1411  }
1412  else
1413  {
1414  if(DistanceStr == AnsiString(OverallDistance))
1415  {
1416  Dist = -1; // i.e.don't change
1417  }
1418  if((SpeedStr == "Mixed") || (SpeedStr == AnsiString(OverallSpeedLimit)))
1419  {
1420  SpeedLimit = -1; // i.e.don't change
1421  }
1422  }
1423  if(((Dist != -1) && (DistanceStr.Length() > 6)) || ((SpeedLimit != -1) && (SpeedStr.Length() > 6)))
1424  {
1425  ShowMessage("One or more entries too long");
1426  Utilities->CallLogPop(11);
1427  return;
1428  }
1429  if((DistanceStr == "") || (SpeedStr == ""))
1430  {
1431  ShowMessage("One or more entries blank");
1432  Utilities->CallLogPop(12);
1433  return;
1434  }
1435  if(SelectLengthsFlag && (Dist != -1))
1436  {
1437  for(int x = 1; x <= DistanceStr.Length(); x++)
1438  {
1439  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1440  {
1441  ShowMessage("Track length value must be a positive whole number, or blank for no change");
1442  Utilities->CallLogPop(1415);
1443  return;
1444  }
1445  }
1446  }
1447  if(!SelectLengthsFlag)
1448  {
1449  for(int x = 1; x <= DistanceStr.Length(); x++)
1450  {
1451  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1452  {
1453  ShowMessage("Distance must be a positive whole number");
1454  Utilities->CallLogPop(13);
1455  return;
1456  }
1457  }
1458  }
1459  if(SelectLengthsFlag && (SpeedLimit != -1))
1460  {
1461  for(int x = 1; x <= SpeedStr.Length(); x++)
1462  {
1463  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1464  {
1465  ShowMessage("Speed limit must be a positive whole number, or blank for no change");
1466  Utilities->CallLogPop(1416);
1467  return;
1468  }
1469  }
1470  }
1471  if(!SelectLengthsFlag && (SpeedStr != "Mixed"))
1472  {
1473  for(int x = 1; x <= SpeedStr.Length(); x++)
1474  {
1475  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1476  {
1477  ShowMessage("Speed limit must be a positive whole number, or 'Mixed'");
1478  Utilities->CallLogPop(14);
1479  return;
1480  }
1481  }
1482  }
1483  if(Dist != -1)
1484  {
1485  Dist = DistanceStr.ToInt();
1486  }
1487  if(SpeedLimit != -1)
1488  {
1489  SpeedLimit = SpeedStr.ToInt();
1490  }
1491 /* don't need this with new condition below
1492  if(SelectLengthsFlag && (Dist != -1) && (Dist < 20))
1493  {
1494  ShowMessage("Track length value must be a minimum of 10m, setting to 10m");
1495  Dist = 20;
1496  }
1497 */
1498  if(((Dist != -1) && (Dist < 10)) || ((SpeedLimit != -1) && (SpeedLimit < 10)) || ((SpeedLimit != -1) && (SpeedLimit > TTrain::MaximumSpeedLimit)))
1499  // new limiting values for v0.6 (used only to fail at either value 0); added TTrain::MaxSpeedLimit at v2.1.0
1500  {
1501  ShowMessage("Lengths must be 10m or more, and speeds must be between 10km/h and 400km/h"); // changed at v2.1.0 to limit max speed
1502  Utilities->CallLogPop(15);
1503  return;
1504  }
1505  DistanceBox->Text = "";
1506  SpeedLimitBox->Text = "";
1507  if(SelectLengthsFlag)
1508  {
1509  int LowSelectHLoc = SelectBitmapHLoc;
1510  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1511  int LowSelectVLoc = SelectBitmapVLoc;
1512  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1513  bool FoundFlag;
1514  bool NamedLocPresent = false;
1515  if((Dist != -1) && (Dist != Track->DefaultTrackLength))
1516  {
1517  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1518  {
1519  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1520  {
1522  {
1523  NamedLocPresent = true;
1524  }
1525  }
1526  }
1527  }
1528  if(NamedLocPresent && (Dist < 50)) // changed in v2.4.0
1529  {
1530  if(!TooShortMessageSentFlag) //added at v2.9.1
1531  {
1532  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might be too unrealistic.\n\nThis message will not be shown again.");
1533  TooShortMessageSentFlag = true; //added at v2.9.1
1534  }
1535  }
1536  if(NamedLocPresent && (Dist > 200)) // changed in v2.4.0
1537  {
1538  if(!TooLongMessageSentFlag) //added at v2.9.1
1539  {
1540  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might be too unrealistic.\n\nThis message will not be shown again.");
1541  TooLongMessageSentFlag = true; //added at v2.9.1
1542  }
1543  }
1544  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1545  {
1546  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1547  {
1548  int VecPos = Track->GetVectorPositionFromTrackMap(34, x, y, FoundFlag);
1549  if(FoundFlag)
1550  {
1551  if(Dist > -1) // && !(Track->IsPlatformOrNamedNonStationLocationPresent(7, x, y)))
1552  {
1553  Track->TrackElementAt(692, VecPos).Length01 = Dist;
1554  if(Track->TrackElementAt(693, VecPos).Length23 != -1)
1555  {
1556  Track->TrackElementAt(694, VecPos).Length23 = Dist;
1557  }
1558  }
1559  if(SpeedLimit > -1)
1560  {
1561  Track->TrackElementAt(695, VecPos).SpeedLimit01 = SpeedLimit;
1562  if(Track->TrackElementAt(696, VecPos).SpeedLimit23 != -1)
1563  {
1564  Track->TrackElementAt(697, VecPos).SpeedLimit23 = SpeedLimit;
1565  }
1566  }
1567  }
1568  }
1569  }
1570  TrackLengthPanel->Visible = false;
1571  SelectLengthsFlag = false; // go back to normal distance setting mode
1572  }
1573  else
1574  {
1575  SetTrackLengths(1, Dist, SpeedLimit);
1576  }
1578  SetLevel1Mode(57);
1580  SetLevel2TrackMode(21);
1581  Utilities->CallLogPop(16);
1582  }
1583  catch(const Exception &e)
1584  {
1585  ErrorLog(6, e.Message);
1586  }
1587 }
1588 
1589 // ---------------------------------------------------------------------------
1590 void __fastcall TInterface::LengthCancelButtonClick(TObject * Sender)
1591 {
1592  try
1593  {
1594  TrainController->LogEvent("LengthCancelButtonClick");
1595  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthCancelButtonClick");
1596  DistanceBox->Text = "";
1597  SpeedLimitBox->Text = "";
1598  TrackLengthPanel->Visible = false;
1599  SelectLengthsFlag = false; // go back to normal distance setting mode
1601  SetLevel1Mode(59);
1603  SetLevel2TrackMode(23);
1604  Utilities->CallLogPop(1169);
1605  }
1606  catch(const Exception &e)
1607  {
1608  ErrorLog(128, e.Message);
1609  }
1610 }
1611 
1612 // ---------------------------------------------------------------------------
1613 void __fastcall TInterface::ResetDefaultLengthButtonClick(TObject *Sender)
1614 {
1615  try
1616  {
1617  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ResetDefaultLengthButtonClick");
1618  TMsgDlgButtons Buttons;
1619  Buttons << mbYes << mbNo;
1620  if(MessageDlg("This will reset the selected elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1621  {
1622  // leave all as was before
1623  Utilities->CallLogPop(17);
1624  return;
1625  }
1626  else
1627  {
1628  TrainController->LogEvent("Accepted ResetDefaultLengthButtonClick");
1629  ResetChangedFileDataAndCaption(25, true); // added after 2.7.0 so only need to save if something changed
1630  DistanceBox->Text = "";
1631  SpeedLimitBox->Text = "";
1632  if(SelectLengthsFlag)
1633  {
1634  int LowSelectHLoc = SelectBitmapHLoc;
1635  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1636  int LowSelectVLoc = SelectBitmapVLoc;
1637  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1638  bool FoundFlag;
1639  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1640  {
1641  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1642  {
1643  int VecPos = Track->GetVectorPositionFromTrackMap(35, x, y, FoundFlag);
1644  if(FoundFlag)
1645  {
1647  if(Track->TrackElementAt(699, VecPos).Length23 != -1)
1648  {
1650  }
1652  if(Track->TrackElementAt(702, VecPos).SpeedLimit23 != -1)
1653  {
1655  }
1656  }
1657  }
1658  }
1659  TrackLengthPanel->Visible = false;
1660 // ClearandRebuildRailway(47); don't need this
1661  SelectLengthsFlag = false; // go back to normal distance setting mode
1662  }
1663  else
1664  {
1665  TrackLengthPanel->Visible = false;
1666  bool FoundFlag;
1667  if(ConstructPrefDir->PrefDirSize() == 0)
1668  {
1669  Utilities->CallLogPop(1120);
1670  return;
1671  }
1672  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1673  {
1674  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(169, x);
1675  TTrackElement & TrackElement = Track->TrackElementAt(37, Track->GetVectorPositionFromTrackMap(40, PrefDirElement.HLoc, PrefDirElement.VLoc,
1676  FoundFlag));
1677  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover) || (TrackElement.TrackType == Bridge))
1678  // only set the relevant track to default length & speed limit
1679  {
1680  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be one of each for points
1681  {
1682  TrackElement.Length01 = Track->DefaultTrackLength;
1683  TrackElement.SpeedLimit01 = Track->DefaultTrackSpeedLimit; // 200km/h = 125mph
1684  }
1685  else
1686  {
1687  TrackElement.Length23 = Track->DefaultTrackLength;
1688  TrackElement.SpeedLimit23 = Track->DefaultTrackSpeedLimit; // 200km/h = 125mph
1689  }
1690  }
1691  else // any other 1 track element, including platforms being present
1692  {
1693  if((PrefDirElement.GetELinkPos() > 1) && (PrefDirElement.GetXLinkPos() > 1))
1694  {
1695  throw Exception("Error, XLinkPos > 1 in SetOneDefaultTrackLength at " + AnsiString(TrackElement.HLoc) + " & " +
1696  AnsiString(TrackElement.VLoc));
1697  }
1698  TrackElement.Length01 = Track->DefaultTrackLength;
1699  TrackElement.SpeedLimit01 = Track->DefaultTrackSpeedLimit; // 200km/h = 125mph
1700  TrackElement.Length23 = -1;
1701  TrackElement.SpeedLimit23 = -1;
1702  }
1703  }
1704  }
1706  SetLevel1Mode(61);
1708  SetLevel2TrackMode(25);
1709  }
1710  Utilities->CallLogPop(18);
1711  }
1712  catch(const Exception &e)
1713  {
1714  ErrorLog(7, e.Message);
1715  }
1716 }
1717 
1718 // ---------------------------------------------------------------------------
1719 void __fastcall TInterface::RestoreAllDefaultLengthsButtonClick(TObject *Sender)
1720 {
1721  try
1722  {
1723  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreAllDefaultLengthsButtonClick");
1724  TMsgDlgButtons Buttons;
1725  Buttons << mbYes << mbNo;
1726  if(MessageDlg("This will reset ALL track elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1727  {
1728  // leave all as was before
1729  Utilities->CallLogPop(19);
1730  return;
1731  }
1732  else
1733  {
1735  }
1736  TrainController->LogEvent("Accepted RestoreAllDefaultLengthsButtonClick");
1737  ResetChangedFileDataAndCaption(26, true); // added after 2.7.0 so only need to save if something changed
1738  DistanceBox->Text = "";
1739  SpeedLimitBox->Text = "";
1740  TrackLengthPanel->Visible = false;
1741  SelectLengthsFlag = false; // go back to normal distance setting mode
1743  SetLevel1Mode(63);
1745  SetLevel2TrackMode(27);
1746  Utilities->CallLogPop(20);
1747  }
1748  catch(const Exception &e)
1749  {
1750  ErrorLog(8, e.Message);
1751  }
1752 }
1753 
1754 // ---------------------------------------------------------------------------
1755 void __fastcall TInterface::ExitTrackButtonClick(TObject *Sender)
1756 {
1757  try
1758  {
1759  TrainController->LogEvent("ExitTrackButtonClick");
1760  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTrackButtonClick");
1761  if(Level2TrackMode == CutMoving)
1762  {
1763  Level2TrackMode = Pasting; // to paste the selection
1764  SetLevel2TrackMode(53);
1765  }
1766  DevelopmentPanel->Visible = false; // development use only
1767  ScreenGridFlag = false;
1768  SelectionValid = false;
1769  Track->SelectGraphicVector.clear();
1770  // delete all unwanted TPictures in UserGraphicMap
1771  if(!Track->UserGraphicMap.empty()) // if empty skip it
1772  {
1773  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1774  do
1775  {
1776  bool GraphicFoundInVector = false;
1777  for(TTrack::TUserGraphicVector::iterator UGVIt = Track->UserGraphicVector.begin(); UGVIt < Track->UserGraphicVector.end(); UGVIt++)
1778  {
1779  if(UGMIt->first == UGVIt->FileName)
1780  {
1781  GraphicFoundInVector = true;
1782  break;
1783  }
1784  }
1785  if(!GraphicFoundInVector)
1786  {
1787  delete UGMIt->second;
1788  Track->UserGraphicMap.erase(UGMIt);
1789  UGMIt = Track->UserGraphicMap.begin(); // reset the iterator because erasing an element it points to invalidates it & if use it after then
1790  // behaviour is undefined, the iteration will end eventually because the map has got shorter after an erase
1791  }
1792  else
1793  {
1794  UGMIt++;
1795  }
1796  }
1797  while(UGMIt != Track->UserGraphicMap.end());
1798  }
1799  Level1Mode = BaseMode;
1800  SetLevel1Mode(2);
1801  Utilities->CallLogPop(1170);
1802  }
1803  catch(const Exception &e)
1804  {
1805  ErrorLog(129, e.Message);
1806  }
1807 }
1808 
1809 // ---------------------------------------------------------------------------
1810 void __fastcall TInterface::TextOrUserGraphicGridButtonClick(TObject *Sender)
1811 {
1812  try
1813  {
1814  TrainController->LogEvent("TextOrUserGraphicGridButtonClick," + AnsiString(TextOrUserGraphicGridVal));
1815  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextOrUserGraphicGridButtonClick");
1816  if(TextOrUserGraphicGridVal == 1)
1817  {
1819  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision2");
1820  }
1821  else if(TextOrUserGraphicGridVal == 2)
1822  {
1824  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision4");
1825  }
1826  else if(TextOrUserGraphicGridVal == 4)
1827  {
1829  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision8");
1830  }
1831  else if(TextOrUserGraphicGridVal == 8)
1832  {
1834  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision16");
1835  }
1836  else
1837  {
1839  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
1840  }
1841  Utilities->CallLogPop(1171);
1842  }
1843  catch(const Exception &e)
1844  {
1845  ErrorLog(130, e.Message);
1846  }
1847 }
1848 
1849 // ---------------------------------------------------------------------------
1850 void __fastcall TInterface::SigAspectButtonClick(TObject *Sender)
1851 {
1852  try
1853  {
1854  TrainController->LogEvent("SigAspectButtonClick," + AnsiString(Track->SignalAspectBuildMode));
1855  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigAspectButtonClick");
1857  {
1859  SigAspectButton->Glyph->LoadFromResourceName(0, "ThreeAspect");
1860  }
1862  {
1864  SigAspectButton->Glyph->LoadFromResourceName(0, "TwoAspect");
1865  }
1867  {
1869  SigAspectButton->Glyph->LoadFromResourceName(0, "GroundSig");
1870 // set all signal glyphs to ground signals
1872  }
1873  else
1874  {
1876  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
1877 // set all signal glyphs to normal signals
1879  }
1880  Utilities->CallLogPop(1869);
1881  }
1882  catch(const Exception &e)
1883  {
1884  ErrorLog(180, e.Message);
1885  }
1886 }
1887 
1888 // ---------------------------------------------------------------------------
1889 void __fastcall TInterface::FontButtonClick(TObject *Sender)
1890 {
1891  try
1892  {
1893  TrainController->LogEvent("FontButtonClick");
1894  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FontButtonClick");
1895  FontDialog->Font = Display->GetFont(); // sets the dialog box font to the currently used font
1896  FontDialog->Execute(); // this displays the dialog box
1897  if(FontDialog->Font->Color == clB5G5R5) // white
1898  {
1899  FontDialog->Font->Color = clB0G0R0; // black - don't store white in font, will display black as white on dark backgrounds
1900  }
1901  Display->SetFont(FontDialog->Font); // sets the displayed font to the output from the dialog box
1902  if(TextBox->Visible)
1903  {
1904  TextBox->SetFocus();
1905  }
1906  else if(LocationNameTextBox->Visible)
1907  {
1908  LocationNameTextBox->SetFocus();
1909  }
1910  Utilities->CallLogPop(1172);
1911  }
1912  catch(const Exception &e)
1913  {
1914  ErrorLog(131, e.Message);
1915  }
1916 }
1917 
1918 // ---------------------------------------------------------------------------
1919 
1920 void __fastcall TInterface::ScreenGridButtonClick(TObject *Sender)
1921 {
1922  try
1923  {
1924  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenGridButtonClick");
1925  if(ScreenGridFlag)
1926  {
1927  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid off");
1928  ScreenGridFlag = false;
1929  }
1930  else
1931  {
1932  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid on");
1933  ScreenGridFlag = true;
1934  }
1936  Utilities->CallLogPop(89);
1937  }
1938  catch(const Exception &e)
1939  {
1940  ErrorLog(33, e.Message);
1941  }
1942 }
1943 
1944 // ---------------------------------------------------------------------------
1945 // PrefDir Interface
1946 // ---------------------------------------------------------------------------
1947 void __fastcall TInterface::PlanPrefDirsMenuItemClick(TObject *Sender) // Mode Menu Item
1948 {
1949  try
1950  {
1951  TrainController->LogEvent("PlanPrefDirsMenuItemClick");
1952  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlanPrefDirsMenuItemClick");
1954  SetLevel1Mode(3);
1955  Utilities->CallLogPop(1173);
1956  }
1957  catch(const Exception &e)
1958  {
1959  ErrorLog(132, e.Message);
1960  }
1961 }
1962 
1963 // ---------------------------------------------------------------------------
1964 void __fastcall TInterface::AddPrefDirButtonClick(TObject *Sender)
1965 {
1966  try
1967  {
1968  TrainController->LogEvent("AddPrefDirButtonClick");
1969  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddPrefDirButtonClick");
1970  if(ConstructPrefDir->PrefDirSize() == 0)
1971  {
1972  ShowMessage("No preferred direction selection");
1973  Utilities->CallLogPop(22);
1974  return;
1975  }
1976  Screen->Cursor = TCursor(-11); // Hourglass;
1978  {
1980  }
1982  SetLevel1Mode(4);
1983  Screen->Cursor = TCursor(-2); // Arrow
1984  Utilities->CallLogPop(23);
1985  }
1986  catch(const Exception &e)
1987  {
1988  ErrorLog(10, e.Message);
1989  }
1990 }
1991 
1992 // ---------------------------------------------------------------------------
1993 void __fastcall TInterface::DeleteAllPrefDirButtonClick(TObject *Sender)
1994 {
1995  try
1996  {
1997  TrainController->LogEvent("DeleteAllPrefDirButtonClick");
1998  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteAllPrefDirButtonClick");
1999  TMsgDlgButtons Buttons;
2000  Buttons << mbYes << mbNo;
2001  if(MessageDlg("Do you really want to clear all preferred directions?", mtWarning, Buttons, 0) == mrNo)
2002  {
2003  Utilities->CallLogPop(24);
2004  return;
2005  }
2006  // leave all as was before pressed DeleteAllPrefDirButton
2007  else
2008  {
2013  SetLevel1Mode(5);
2014  }
2015  Utilities->CallLogPop(25);
2016  }
2017  catch(const Exception &e)
2018  {
2019  ErrorLog(11, e.Message);
2020  }
2021 }
2022 // ---------------------------------------------------------------------------
2023 
2024 void __fastcall TInterface::DeleteOnePrefDirButtonClick(TObject *Sender)
2025 {
2026  try
2027  {
2028  TrainController->LogEvent("DeleteOnePrefDirButtonClick");
2029  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteOnePrefDirButtonClick");
2030  ResetChangedFileDataAndCaption(18, false);
2031 // RlyFile = false; - don't alter this just for PrefDir changes
2032  Screen->Cursor = TCursor(-11); // Hourglass;
2033  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
2034  {
2037  }
2040  SetLevel1Mode(81); // all PrefDir truncated
2041  Screen->Cursor = TCursor(-2); // Arrow
2042  Utilities->CallLogPop(1591);
2043  }
2044  catch(const Exception &e)
2045  {
2046  ErrorLog(46, e.Message);
2047  }
2048 }
2049 
2050 // ---------------------------------------------------------------------------
2051 
2052 void __fastcall TInterface::ExitPrefDirButtonClick(TObject *Sender)
2053 {
2054  try
2055  {
2056  TrainController->LogEvent("ExitPrefDirButtonClick");
2057  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitPrefDirButtonClick");
2058  Level1Mode = BaseMode;
2059  SetLevel1Mode(6);
2060  Utilities->CallLogPop(1554);
2061  }
2062  catch(const Exception &e)
2063  {
2064  ErrorLog(133, e.Message);
2065  }
2066 }
2067 
2068 // ---------------------------------------------------------------------------
2069 // Operate Railway Interface
2070 // ---------------------------------------------------------------------------
2071 void __fastcall TInterface::OperateRailwayMenuItemClick(TObject *Sender) // Mode Menu Item
2072 {
2073  try
2074  {
2075  TrainController->LogEvent("OperateRailwayMenuItemClick");
2076  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateRailwayMenuItemClick");
2077  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
2078  AllRoutes->NextRouteID = 0; // reset to 0 whenever enter operating mode
2079  Level1Mode = OperMode;
2080  SetLevel1Mode(7);
2081  Utilities->CallLogPop(26);
2082  }
2083  catch(const Exception &e)
2084  {
2085  ErrorLog(12, e.Message);
2086  }
2087 }
2088 
2089 // ---------------------------------------------------------------------------
2090 void __fastcall TInterface::OperateButtonClick(TObject *Sender)
2091 {
2092  try
2093  {
2094  TrainController->LogEvent("StartOperationButtonClick");
2095  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateButtonClick");
2097  {
2099  SetLevel2OperMode(0);
2100  }
2101  else
2102  {
2104  SetLevel2OperMode(1);
2105  }
2106  Utilities->CallLogPop(1175);
2107  }
2108  catch(const Exception &e)
2109  {
2110  ErrorLog(37, e.Message);
2111  }
2112 }
2113 
2114 // ---------------------------------------------------------------------------
2115 void __fastcall TInterface::AutoSigsButtonClick(TObject *Sender)
2116 // must have PrefDirs to be available
2117 {
2118  try
2119  {
2120  TrainController->LogEvent("AutoSigsButtonClick");
2121  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AutoSigsButtonClick");
2122  AutoSigsFlag = true;
2123  PreferredRoute = true;
2124  ConsecSignalsRoute = true;
2125 
2126  AutoSigsButton->Enabled = false;
2127  SigPrefConsecButton->Enabled = true;
2128  SigPrefNonConsecButton->Enabled = true;
2129  UnrestrictedButton->Enabled = true;
2130 
2131  InfoPanel->Visible = true;
2132  if(Level2OperMode == PreStart)
2133  {
2134  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2135  }
2136  else
2137  {
2138  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2139  }
2140  InfoCaptionStore = InfoPanel->Caption;
2141  AutoRouteStartMarker->PlotOriginal(1, Display); // if overlay not plotted will ignore
2142  SigRouteStartMarker->PlotOriginal(2, Display); // if overlay not plotted will ignore
2143  NonSigRouteStartMarker->PlotOriginal(3, Display); // if overlay not plotted will ignore
2145  Utilities->CallLogPop(28);
2146  }
2147  catch(const Exception &e)
2148  {
2149  ErrorLog(14, e.Message);
2150  }
2151 }
2152 
2153 // ---------------------------------------------------------------------------
2154 
2155 void __fastcall TInterface::SigPrefConsecButtonClick(TObject *Sender)
2156 // must have PrefDirs to be available
2157 {
2158  try
2159  {
2160  TrainController->LogEvent("SigPrefButtonClick");
2161  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2162  AutoSigsFlag = false;
2163  PreferredRoute = true;
2164  ConsecSignalsRoute = true;
2165 
2166  AutoSigsButton->Enabled = true;
2167  SigPrefConsecButton->Enabled = false;
2168  SigPrefNonConsecButton->Enabled = true;
2169  UnrestrictedButton->Enabled = true;
2170 
2171  InfoPanel->Visible = true;
2172  if(Level2OperMode == PreStart)
2173  {
2174  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2175  }
2176  else
2177  {
2178  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2179  }
2180  InfoCaptionStore = InfoPanel->Caption;
2181  AutoRouteStartMarker->PlotOriginal(43, Display); // if overlay not plotted will ignore
2182  SigRouteStartMarker->PlotOriginal(44, Display); // if overlay not plotted will ignore
2183  NonSigRouteStartMarker->PlotOriginal(45, Display); // if overlay not plotted will ignore
2185  Utilities->CallLogPop(2265);
2186  }
2187  catch(const Exception &e)
2188  {
2189  ErrorLog(221, e.Message);
2190  }
2191 }
2192 
2193 // ---------------------------------------------------------------------------
2194 
2195 void __fastcall TInterface::SigPrefNonConsecButtonClick(TObject *Sender)
2196 // must have PrefDirs to be available
2197 {
2198  try
2199  {
2200  TrainController->LogEvent("SigPrefButtonClick");
2201  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2202  AutoSigsFlag = false;
2203  PreferredRoute = true;
2204  ConsecSignalsRoute = false;
2205 
2206  AutoSigsButton->Enabled = true;
2207  SigPrefConsecButton->Enabled = true;
2208  SigPrefNonConsecButton->Enabled = false;
2209  UnrestrictedButton->Enabled = true;
2210 
2211  InfoPanel->Visible = true;
2212  if(Level2OperMode == PreStart)
2213  {
2214  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2215  }
2216  else
2217  {
2218  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2219  }
2220  InfoCaptionStore = InfoPanel->Caption;
2221  AutoRouteStartMarker->PlotOriginal(4, Display); // if overlay not plotted will ignore
2222  SigRouteStartMarker->PlotOriginal(5, Display); // if overlay not plotted will ignore
2223  NonSigRouteStartMarker->PlotOriginal(6, Display); // if overlay not plotted will ignore
2225  Utilities->CallLogPop(29);
2226  }
2227  catch(const Exception &e)
2228  {
2229  ErrorLog(15, e.Message);
2230  }
2231 }
2232 
2233 // ---------------------------------------------------------------------------
2234 void __fastcall TInterface::UnrestrictedButtonClick(TObject *Sender)
2235 {
2236  try
2237  {
2238  TrainController->LogEvent("NoSigNonPrefButtonClick");
2239  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NoSigNonPrefButtonClick");
2240  AutoSigsFlag = false;
2241  PreferredRoute = false;
2242  ConsecSignalsRoute = false;
2243  if(EveryPrefDir->PrefDirSize() > 0)
2244  {
2245  AutoSigsButton->Enabled = true;
2246  SigPrefConsecButton->Enabled = true;
2247  SigPrefNonConsecButton->Enabled = true;
2248  UnrestrictedButton->Enabled = false;
2249  }
2250  else
2251  {
2252  AutoSigsButton->Enabled = false;
2253  SigPrefConsecButton->Enabled = false;
2254  SigPrefNonConsecButton->Enabled = false;
2255  UnrestrictedButton->Enabled = false;
2256  }
2257  InfoPanel->Visible = true;
2258  if(Level2OperMode == PreStart)
2259  {
2260  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2261  }
2262  else
2263  {
2264  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2265  }
2266  InfoCaptionStore = InfoPanel->Caption;
2267  AutoRouteStartMarker->PlotOriginal(7, Display); // if overlay not plotted will ignore
2268  SigRouteStartMarker->PlotOriginal(8, Display); // if overlay not plotted will ignore
2269  NonSigRouteStartMarker->PlotOriginal(9, Display); // if overlay not plotted will ignore
2271  Utilities->CallLogPop(30);
2272  }
2273  catch(const Exception &e)
2274  {
2275  ErrorLog(16, e.Message);
2276  }
2277 }
2278 
2279 // ---------------------------------------------------------------------------
2280 void __fastcall TInterface::RouteCancelButtonClick(TObject *Sender)
2281 {
2282  try
2283  {
2284  TrainController->LogEvent("RouteCancelButtonClick");
2285  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RouteCancelButtonClick");
2286  RouteCancelFlag = true;
2287  InfoPanel->Visible = true;
2288  InfoPanel->Caption = "ROUTE CANCELLING: Right click on truncate element, first element to cancel (anywhere else to skip)";
2289  RouteCancelButton->Enabled = false;
2290  AutoRouteStartMarker->PlotOriginal(32, Display); // if overlay not plotted will ignore
2291  SigRouteStartMarker->PlotOriginal(33, Display); // if overlay not plotted will ignore
2292  NonSigRouteStartMarker->PlotOriginal(34, Display); // if overlay not plotted will ignore
2293  Utilities->CallLogPop(1176);
2294  }
2295  catch(const Exception &e)
2296  {
2297  ErrorLog(35, e.Message);
2298  }
2299 }
2300 
2301 // ---------------------------------------------------------------------------
2302 void __fastcall TInterface::PerformanceLogButtonClick(TObject *Sender)
2303 {
2304  try
2305  {
2306  TrainController->LogEvent("PerformanceLogButtonClick");
2307  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformanceLogButtonClick");
2309  {
2310  ShowPerformancePanel = true;
2311  PerformancePanel->Visible = true;
2312  PerformanceLogButton->Glyph->LoadFromResourceName(0, "HideLog");
2313  }
2314  else
2315  {
2316  ShowPerformancePanel = false;
2317  PerformancePanel->Visible = false;
2318  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2319  }
2320  Utilities->CallLogPop(1177);
2321  }
2322  catch(const Exception &e)
2323  {
2324  ErrorLog(36, e.Message);
2325  }
2326 }
2327 // ---------------------------------------------------------------------------
2328 
2329 void __fastcall TInterface::ExitOperationButtonClick(TObject *Sender)
2330 {
2331  try
2332  {
2333  TrainController->LogEvent("ExitOperationButtonClick");
2334  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitOperationButtonClick");
2336  {
2337  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
2338  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2340  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
2341  TrainController->BaseTime = TDateTime::CurrentDateTime();
2343  if(button == IDNO)
2344  {
2345  Utilities->CallLogPop(751);
2346  return;
2347  }
2348  }
2349  Track->ResetSignals(1);
2350  Track->ResetPoints(1);
2351  TrainController->SendPerformanceSummary(0, Utilities->PerformanceFile); // must come before trains finished becuase examines the train vectors
2352  Utilities->PerformanceFile.close();
2355  RouteMode = None;
2356  PreferredRoute = true; // default starting conditions
2357  ConsecSignalsRoute = true; // default starting conditions
2359  ShowPerformancePanel = false;
2360  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2361  ShowOperatorActionPanel = false; // new at v2.2.0
2362  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
2363  PerformanceLogBox->Lines->Clear();
2364  PerformancePanel->Visible = false;
2365  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
2366  PerformancePanel->Left = MainScreen->Left;
2367 // TipButton->Glyph->LoadFromResourceName(0, "ShowLog"); //'Trains in play' new at v2.2.0
2368  OAListBox->Clear();
2369  OperatorActionPanel->Visible = false;
2370  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height;
2371  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
2372  ;
2374  AllRoutes->LockedRouteVector.clear();
2375  Level1Mode = BaseMode;
2376  SetLevel1Mode(8); // calls Clearand...
2377  Utilities->CallLogPop(1555);
2378  }
2379  catch(const Exception &e)
2380  {
2381  ErrorLog(13, e.Message);
2382  }
2383 }
2384 
2385 // ---------------------------------------------------------------------------
2386 // Menu Interface (for items not already covered above)
2387 // ---------------------------------------------------------------------------
2388 void __fastcall TInterface::LoadRailwayMenuItemClick(TObject *Sender)
2389 {
2390  try
2391  {
2392  TrainController->LogEvent("LoadRailwayMenuItemClick");
2393  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadRailwayMenuItemClick");
2394  if(!ClearEverything(1))
2395  {
2396  Utilities->CallLogPop(1139);
2397  return;
2398  }
2399  // LoadRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly"; //as was
2400  // changed at v2.0.0 (Embarcadero change) to show all files together
2401  LoadRailwayDialog->Filter = "Railway file (*.rly or *.dev)|*.rly; *.dev";
2402  if(LoadRailwayDialog->Execute())
2403  {
2404  if(LoadRailwayDialog->InitialDir != TPath::GetDirectoryName(LoadRailwayDialog->FileName)) // new at v2.6.0 to retain a new directory
2405  {
2406  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2407  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2408  }
2409  TrainController->LogEvent("LoadRailway " + AnsiString(LoadRailwayDialog->FileName));
2410  LoadRailway(0, AnsiString(LoadRailwayDialog->FileName));
2411  }
2412  // else ShowMessage("Load Aborted"); drop this
2413  // Display->Update(); //display updated in ClearandRebuildRailway
2414  Track->CalcHLocMinEtc(9);
2415  Level1Mode = BaseMode;
2418  SetLevel1Mode(11); // calls Clearand... to plot the new railway
2419  Utilities->CallLogPop(31);
2420  }
2421  catch(const Exception &e)
2422  {
2423  ErrorLog(17, e.Message);
2424  }
2425 }
2426 // ---------------------------------------------------------------------------
2427 
2428 void TInterface::LoadRailway(int Caller, AnsiString LoadFileName)
2429 {
2430  // display of the loaded railway covered in the calling routine
2431  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRailway," + LoadFileName);
2432  if(FileIntegrityCheck(0, LoadFileName.c_str()))
2433  {
2434  Screen->Cursor = TCursor(-11); // Hourglass;
2435  std::ifstream VecFile(LoadFileName.c_str());
2436  if(!(VecFile.fail()))
2437  {
2438  AnsiString TempString = Utilities->LoadFileString(VecFile); // version number
2439  int TempOffsetHHome = Utilities->LoadFileInt(VecFile);
2440  int TempOffsetVHome = Utilities->LoadFileInt(VecFile);
2441  bool GraphicsFollow = false;
2442  // can't load DisplayOffsetH & VHome until after LoadTrack as that calls TrackClear & zeroes them
2443 // load track elements
2444  Track->LoadTrack(1, VecFile, GraphicsFollow);
2445 // load text elements
2446  TextHandler->LoadText(0, VecFile);
2447 // load PrefDir elements
2448  EveryPrefDir->LoadPrefDir(0, VecFile);
2449  if(GraphicsFollow)
2450  {
2451 // load user graphics
2452  Track->LoadGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder
2453  }
2454  EveryPrefDir->CheckPrefDirAgainstTrackVector(0); // clears PrefDir if any discrepancies found
2455  VecFile.close();
2456  Display->DisplayOffsetHHome = TempOffsetHHome;
2457  Display->DisplayOffsetVHome = TempOffsetVHome;
2459 
2460  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
2461  TempFont->Style.Clear();
2462  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
2463  TempFont->Size = 10;
2464  TempFont->Color = clB0G0R0;
2465  TempFont->Charset = (TFontCharset)(0);
2466  MainScreen->Canvas->Font->Assign(TempFont);
2467  delete TempFont;
2468 
2469 // calculate starting zoomed out offset values - same as when zoom out button clicked
2470  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
2471 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
2472  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
2473  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
2474  if((LeftExcess > 0) && (RightExcess > 0))
2475  {
2476  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
2477  }
2478  else if((LeftExcess > 0) && (RightExcess <= 0))
2479  {
2480  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
2481  (Utilities->ScreenElementWidth / 2); // normalise to nearest half screen
2482  }
2483  else if((LeftExcess <= 0) && (RightExcess > 0))
2484  {
2485  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
2486  }
2487  else
2488  {
2489  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
2490 
2491  }
2492  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
2493  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
2494  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
2495  if((TopExcess > 0) && (BotExcess > 0))
2496  {
2497  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
2498  }
2499  else if((TopExcess > 0) && (BotExcess <= 0))
2500  {
2501  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
2502  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
2503  }
2504  else if((TopExcess <= 0) && (BotExcess > 0))
2505  {
2506  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
2507  }
2508  else
2509  {
2510  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
2511  }
2512 // all above same as when zoom out button clicked
2513  Display->DisplayZoomOutOffsetVHome = Display->DisplayZoomOutOffsetV; // now set zoomed out 'home' values
2515 
2516  SavedFileName = AnsiString(LoadRailwayDialog->FileName); // includes the full PrefDir
2517  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
2518  {
2519  Track->DuplicatedLocationName(1, true);
2520  char LastChar = SavedFileName[SavedFileName.Length()];
2521  if((LastChar == 'y') || (LastChar == 'Y'))
2522  {
2523  if(!(Track->IsReadyForOperation(false)))
2524  {
2525  ShowMessage("Railway not ready for operation so unable to load as a .rly file. Loading as a new railway under development");
2526  SavedFileName = "";
2527  RlyFile = false;
2528  RailwayTitle = "";
2529  TimetableTitle = "";
2530  SetCaption(5);
2531  Track->CalcHLocMinEtc(1);
2532  Screen->Cursor = TCursor(-2); // Arrow
2533  Level1Mode = BaseMode;
2534  SetLevel1Mode(9);
2535  session_api_->dump(); // update session INI file //added at v2.10.0
2536  Utilities->CallLogPop(1136);
2537  return;
2538  }
2539  else
2540  {
2541  RlyFile = true;
2542  }
2543  }
2544  else
2545  {
2546  RlyFile = false;
2547  }
2548  }
2549  else
2550  {
2551  RlyFile = false;
2552  }
2553  FileChangedFlag = false;
2554  for(int x = AnsiString(LoadRailwayDialog->FileName).Length(); x > 0; x--)
2555  {
2556  if(AnsiString(LoadRailwayDialog->FileName)[x] == '\\')
2557  {
2558  RailwayTitle = AnsiString(LoadRailwayDialog->FileName).SubString(x + 1, AnsiString(LoadRailwayDialog->FileName).Length() - x - 4);
2559  TimetableTitle = "";
2560  SetCaption(6);
2561  break;
2562  }
2563  }
2564  } // if(VecFile)
2565  else
2566  {
2567  ShowMessage("File open failed prior to load");
2568  }
2569  Screen->Cursor = TCursor(-2); // Arrow
2570  } // if(FileIntegrityCheck(LoadRailwayDialog->FileName.c_str()))
2571  else
2572  {
2573  ShowMessage("File integrity check failed - unable to load " + LoadFileName + ". Please check that the file exists and is spelled correctly.");
2574  }
2575  session_api_->dump(); // update session INI file //added at v2.10.0
2576  Utilities->CallLogPop(1774);
2577 }
2578 
2579 // ---------------------------------------------------------------------------
2580 
2581 void __fastcall TInterface::SaveMenuItemClick(TObject *Sender)
2582 {
2583 // save under existing name
2584 // no need to alter RlyFile for saving under existing name
2585 
2586  try
2587  {
2588  TrainController->LogEvent("SaveMenuItemClick, " + SavedFileName);
2589  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveMenuItemClick");
2590  Screen->Cursor = TCursor(-11); // Hourglass;
2591  std::ofstream VecFile(SavedFileName.c_str());
2592  if(!(VecFile.fail()))
2593  {
2597  // save track elements
2598  if(Track->UserGraphicVector.empty())
2599  {
2600  Track->SaveTrack(3, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2601  }
2602  else
2603  {
2604  Track->SaveTrack(8, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2605  }
2606  // save text elements
2607  TextHandler->SaveText(0, VecFile);
2608  // save PrefDir elements
2609  EveryPrefDir->SavePrefDirVector(0, VecFile);
2610  if(!Track->UserGraphicVector.empty())
2611  {
2612  // save user graphics
2613  Track->SaveUserGraphics(0, VecFile);
2614  }
2615  FileChangedFlag = false;
2616  VecFile.close();
2617  }
2618  else
2619  {
2620  ShowMessage("File open failed prior to save");
2621  }
2622  Screen->Cursor = TCursor(-2); // Arrow
2623  Level1Mode = BaseMode;
2624  SetLevel1Mode(12); // to disable the save option
2625  Utilities->CallLogPop(1178);
2626  }
2627  catch(const Exception &e)
2628  {
2629  ErrorLog(135, e.Message);
2630  }
2631 }
2632 
2633 // ---------------------------------------------------------------------------
2634 void __fastcall TInterface::SaveAsMenuItemClick(TObject *Sender)
2635 {
2636  try
2637  {
2638  TrainController->LogEvent("SaveAsMenuItemClick");
2639  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveAsMenuItemClick");
2640  SaveAsSubroutine(0);
2641  Utilities->CallLogPop(32);
2642  }
2643  catch(const Exception &e)
2644  {
2645  ErrorLog(18, e.Message);
2646  }
2647 }
2648 
2649 // ---------------------------------------------------------------------------
2650 
2651 void __fastcall TInterface::SaveImageNoGridMenuItemClick(TObject *Sender)
2652 {
2653  // need to stop clock in case invoke during operation
2654  try
2655  {
2656  TrainController->LogEvent("SaveImageNoGridMenuItemClick");
2657  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageNoGridMenuItemClick");
2658  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2659  {
2660  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2661  Utilities->CallLogPop(1695);
2662  return;
2663  }
2664  Screen->Cursor = TCursor(-11); // Hourglass;
2665  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2667  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2668  // format "16/06/2009 20:55:17"
2669  // avoid characters in filename:= / \ : * ? " < > |
2670  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2671  AnsiString ShortName = "";
2672  for(int x = ImageFileName.Length(); x > 0; x--)
2673  {
2674  if(ImageFileName[x] == '\\')
2675  {
2676  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2677  break;
2678  }
2679  }
2680  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2681  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2682  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2683 
2684  int HPosMin = Track->GetHLocMin() * 16;
2685  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2686  int VPosMin = Track->GetVLocMin() * 16;
2687  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2688  RailwayImage->Width = HPosMax - HPosMin;
2689  RailwayImage->Height = VPosMax - VPosMin;
2690 
2691  // need to check if there is any text that extends past HPosMax or below VPosMax
2692  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2693  if(!TextHandler->TextVector.empty())
2694  {
2695  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2696  {
2697  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2698  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2699  if(NewWidth > RailwayImage->Width)
2700  {
2701  RailwayImage->Width = NewWidth;
2702  }
2703  if(NewHeight > RailwayImage->Height)
2704  {
2705  RailwayImage->Height = NewHeight;
2706  }
2707  }
2708  }
2709  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2710  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2711  RailwayImage->Canvas->FillRect(Rect);
2712 
2713  // write graphics first so text & track overwrite
2714  Track->WriteGraphicsToImage(0, RailwayImage);
2715  // then write track & text so text overwrites graphics & inactive elements //changed name & added text after inactives at v2.10.0
2716  Track->WriteTrackAndTextToImage(0, RailwayImage);
2717 
2718  RailwayImage->SaveToFile(ImageFileName);
2719  delete RailwayImage;
2720  TrainController->BaseTime = TDateTime::CurrentDateTime();
2722  Screen->Cursor = TCursor(-2); // Arrow
2723  Utilities->CallLogPop(1535);
2724  }
2725  catch(const Exception &e) //non-error catch (partial)
2726  {
2727  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2728  {
2729  Screen->Cursor = TCursor(-2); // Arrow;
2730  UnicodeString MessageStr = "Insufficient memory available to store this image";
2731  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2732  Utilities->CallLogPop(2297);
2733  }
2734  else
2735  {
2736  ErrorLog(42, e.Message);
2737  }
2738  }
2739 }
2740 
2741 // ---------------------------------------------------------------------------
2742 
2743 void __fastcall TInterface::SaveImageAndGridMenuItemClick(TObject *Sender)
2744 {
2745  // need to stop clock in case invoke during operation
2746  try
2747  {
2748  TrainController->LogEvent("SaveImageAndGridMenuItemClick");
2749  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndGridMenuItemClick");
2750  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2751  {
2752  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2753  Utilities->CallLogPop(1696);
2754  return;
2755  }
2756  Screen->Cursor = TCursor(-11); // Hourglass;
2757  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2759  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2760  // format "16/06/2009 20:55:17"
2761  // avoid characters in filename:= / \ : * ? " < > |
2762  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2763  AnsiString ShortName = "";
2764  for(int x = ImageFileName.Length(); x > 0; x--)
2765  {
2766  if(ImageFileName[x] == '\\')
2767  {
2768  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2769  break;
2770  }
2771  }
2772  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2773  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2774  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2775  int HPosMin = Track->GetHLocMin() * 16;
2776  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2777  int VPosMin = Track->GetVLocMin() * 16;
2778  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2779  RailwayImage->Width = HPosMax - HPosMin;
2780  RailwayImage->Height = VPosMax - VPosMin;
2781 
2782  // need to check if there is any text that extends past HPosMax or below VPosMax
2783  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2784  if(!TextHandler->TextVector.empty())
2785  {
2786  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2787  {
2788  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2789  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2790  if(NewWidth > RailwayImage->Width)
2791  {
2792  RailwayImage->Width = NewWidth;
2793  }
2794  if(NewHeight > RailwayImage->Height)
2795  {
2796  RailwayImage->Height = NewHeight;
2797  }
2798  }
2799  }
2800  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2801  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2802  RailwayImage->Canvas->FillRect(Rect);
2803 
2804  // write the grid first so all else on top
2805  for(int x = 0; x < ((RailwayImage->Width) / 16); x++)
2806  {
2807  for(int y = 0; y < ((RailwayImage->Height) / 16); y++)
2808  {
2809  RailwayImage->Canvas->Draw((x * 16), (y * 16), RailGraphics->bmGrid); // graphic is black on white so no need to change
2810  }
2811  }
2812  // write graphics next so text & track overwrite
2813  Track->WriteGraphicsToImage(1, RailwayImage);
2814  // then write track & text so text overwrites graphics & inactive elements
2815  Track->WriteTrackAndTextToImage(1, RailwayImage); //changed name & added text after inactives at v2.10.0
2816  RailwayImage->SaveToFile(ImageFileName);
2817  delete RailwayImage;
2818  TrainController->BaseTime = TDateTime::CurrentDateTime();
2820  Screen->Cursor = TCursor(-2); // Arrow
2821  Utilities->CallLogPop(1536);
2822  }
2823  catch(const Exception &e) //non-error catch (partial)
2824  {
2825  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2826  {
2827  Screen->Cursor = TCursor(-2); // Arrow;
2828  UnicodeString MessageStr = "Insufficient memory available to store this image";
2829  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2830  Utilities->CallLogPop(2298);
2831  }
2832  else
2833  {
2834  ErrorLog(43, e.Message);
2835  }
2836  }
2837 }
2838 // ---------------------------------------------------------------------------
2839 
2840 void __fastcall TInterface::SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
2841 {
2842  // need to stop clock in case invoke during operation
2843  try
2844  {
2845  TrainController->LogEvent("SaveImageAndPrefDirsMenuItemClick");
2846  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndPrefDirsMenuItemClick");
2847  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2848  {
2849  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2850  Utilities->CallLogPop(1697);
2851  return;
2852  }
2853  Screen->Cursor = TCursor(-11); // Hourglass;
2854  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2856  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2857  // format "16/06/2009 20:55:17"
2858  // avoid characters in filename:= / \ : * ? " < > |
2859  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2860  AnsiString ShortName = "";
2861  for(int x = ImageFileName.Length(); x > 0; x--)
2862  {
2863  if(ImageFileName[x] == '\\')
2864  {
2865  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2866  break;
2867  }
2868  }
2869  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2870  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2871  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2872  int HPosMin = Track->GetHLocMin() * 16;
2873  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2874  int VPosMin = Track->GetVLocMin() * 16;
2875  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2876  RailwayImage->Width = HPosMax - HPosMin;
2877  RailwayImage->Height = VPosMax - VPosMin;
2878 
2879  // need to check if there is any text that extends past HPosMax or below VPosMax
2880  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2881  if(!TextHandler->TextVector.empty())
2882  {
2883  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2884  {
2885  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2886  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2887  if(NewWidth > RailwayImage->Width)
2888  {
2889  RailwayImage->Width = NewWidth;
2890  }
2891  if(NewHeight > RailwayImage->Height)
2892  {
2893  RailwayImage->Height = NewHeight;
2894  }
2895  }
2896  }
2897  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2898  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2899  RailwayImage->Canvas->FillRect(Rect);
2900 
2901  // write graphics first so text & track overwrite
2902  Track->WriteGraphicsToImage(2, RailwayImage);
2903  // then write track & text so text overwrites graphics & inactive elements
2904  Track->WriteTrackAndTextToImage(2, RailwayImage); //changed name & added text after inactives at v2.10.0
2905  EveryPrefDir->WritePrefDirToImage(0, RailwayImage);
2906  RailwayImage->SaveToFile(ImageFileName);
2907  delete RailwayImage;
2908  TrainController->BaseTime = TDateTime::CurrentDateTime();
2910  Screen->Cursor = TCursor(-2); // Arrow
2911  Utilities->CallLogPop(1566);
2912  }
2913  catch(const Exception &e) //non-error catch (partial)
2914  {
2915  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2916  {
2917  Screen->Cursor = TCursor(-2); // Arrow;
2918  UnicodeString MessageStr = "Insufficient memory available to store this image";
2919  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2920  Utilities->CallLogPop(2299);
2921  }
2922  else
2923  {
2924  ErrorLog(45, e.Message);
2925  }
2926  }
2927 }
2928 // ---------------------------------------------------------------------------
2929 
2930 void __fastcall TInterface::SaveOperatingImageMenuItemClick(TObject *Sender)
2931 {
2932  // need to stop clock
2933  try
2934  {
2935  TrainController->LogEvent("SaveOperatingImageMenuItemClick");
2936  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveOperatingImageMenuItemClick");
2937  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2938  {
2939  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2940  Utilities->CallLogPop(1702);
2941  return;
2942  }
2943  Screen->Cursor = TCursor(-11); // Hourglass;
2944  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2946 
2947  AnsiString TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
2948  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
2949  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2950  // format "16/06/2009 20:55:17"
2951  // avoid characters in filename:= / \ : * ? " < > |
2952  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
2953  "; " + TimetableTitle + ".bmp";
2954  AnsiString ShortName = "";
2955  for(int x = ImageFileName.Length(); x > 0; x--)
2956  {
2957  if(ImageFileName[x] == '\\')
2958  {
2959  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2960  break;
2961  }
2962  }
2963  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2964  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2965  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2966  int HPosMin = Track->GetHLocMin() * 16;
2967  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2968  int VPosMin = Track->GetVLocMin() * 16;
2969  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2970  RailwayImage->Width = HPosMax - HPosMin;
2971  RailwayImage->Height = VPosMax - VPosMin;
2972 
2973  // need to check if there is any text that extends past HPosMax or below VPosMax
2974  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2975  if(!TextHandler->TextVector.empty())
2976  {
2977  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2978  {
2979  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2980  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2981  if(NewWidth > RailwayImage->Width)
2982  {
2983  RailwayImage->Width = NewWidth;
2984  }
2985  if(NewHeight > RailwayImage->Height)
2986  {
2987  RailwayImage->Height = NewHeight;
2988  }
2989  }
2990  }
2991  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2992  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2993  RailwayImage->Canvas->FillRect(Rect);
2994 
2995  // write graphics first so text & track overwrite
2996  Track->WriteGraphicsToImage(3, RailwayImage);
2997  // then write track and text so both overwrite graphics & text overwrites inactive elements
2998  Track->WriteOperatingTrackAndTextToImage(0, RailwayImage); // need points with single fillets, signals with colours, gaps all connected
2999  AllRoutes->WriteAllRoutesToImage(0, RailwayImage);
3000 // add any locked route markers
3001  if(!AllRoutes->LockedRouteVector.empty())
3002  {
3003  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
3004  {
3005  TOneRoute Route = AllRoutes->GetFixedRouteAt(167, LRVIT->RouteNumber);
3006  int x = Route.PrefDirSize() - 1;
3007  bool BreakFlag = false;
3008  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(188, x);
3009  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
3010  {
3011  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
3012  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
3013  if(!(AllRoutes->TrackIsInARoute(13, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
3014  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
3015  {
3016  BreakFlag = true;
3017  break; // train removed earlier element from route so stop here
3018  }
3019  x--;
3020  PrefDirElement = Route.GetFixedPrefDirElementAt(180, x);
3021  }
3022  if(!BreakFlag)
3023  {
3024  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
3025  {
3026  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
3027  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
3028  }
3029  }
3030  }
3031  }
3032  TrainController->WriteTrainsToImage(0, RailwayImage);
3033  RailwayImage->SaveToFile(ImageFileName);
3034  delete RailwayImage;
3035  TrainController->BaseTime = TDateTime::CurrentDateTime();
3037  Screen->Cursor = TCursor(-2); // Arrow
3038  Utilities->CallLogPop(1703);
3039  }
3040  catch(const Exception &e) //non-error catch (partial)
3041  {
3042  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
3043  {
3044  Screen->Cursor = TCursor(-2); // Arrow;
3045  UnicodeString MessageStr = "Insufficient memory available to store this image";
3046  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
3047  Utilities->CallLogPop(2300);
3048  }
3049  else
3050  {
3051  ErrorLog(113, e.Message); // NB: DO NOT CHANGE THIS ERROR NUMBER - THE DISPLAYED MESSAGE DEPENDS ON IT
3052  }
3053  }
3054 }
3055 
3056 // ---------------------------------------------------------------------------
3057 
3058 void __fastcall TInterface::SaveHeaderMenu1Click(TObject *Sender)
3059 {
3060 //
3061  try
3062  {
3063  TrainController->LogEvent("SaveHeaderMenu1Click");
3064  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveHeaderMenu1Click");
3065  if(Sender == SaveSessionButton)
3066  {
3067  SaveSessionFlag = true;
3068  }
3069  else if(SavedFileName == "") // use 'Save As' function
3070  {
3071  SaveAsSubroutine(1);
3072  }
3073  else // ordinary save
3074  {
3075  Screen->Cursor = TCursor(-11); // Hourglass;
3076  std::ofstream VecFile(SavedFileName.c_str());
3077  if(!(VecFile.fail()))
3078  {
3082  // save track elements
3083  if(Track->UserGraphicVector.empty())
3084  {
3085  Track->SaveTrack(9, VecFile, false); // false for no graphics (**Active elements** saved as marker)
3086  }
3087  else
3088  {
3089  Track->SaveTrack(10, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
3090  }
3091  // save text elements
3092  TextHandler->SaveText(5, VecFile);
3093  // save PrefDir elements
3094  EveryPrefDir->SavePrefDirVector(8, VecFile);
3095  if(!Track->UserGraphicVector.empty())
3096  {
3097  // save user graphics
3098  Track->SaveUserGraphics(1, VecFile);
3099  }
3100  FileChangedFlag = false;
3101  VecFile.close();
3102  }
3103  else
3104  {
3105  ShowMessage("Railway failed to save - can't open file");
3106  }
3107  Screen->Cursor = TCursor(-2); // Arrow
3108  }
3109  Utilities->CallLogPop(1552);
3110  }
3111  catch(const Exception &e)
3112  {
3113  ErrorLog(44, e.Message);
3114  }
3115 }
3116 
3117 // ---------------------------------------------------------------------------
3118 void __fastcall TInterface::LoadSessionMenuItemClick(TObject *Sender)
3119 {
3120  try
3121  {
3122  TrainController->LogEvent("LoadSessionMenuItemClick");
3123  LoadSessionFlag = true; // load session within ClockTimer2
3124  }
3125  catch(const Exception &e)
3126  {
3127  ErrorLog(136, e.Message);
3128  }
3129 }
3130 
3131 // ---------------------------------------------------------------------------
3132 void __fastcall TInterface::ClearAllMenuItemClick(TObject *Sender)
3133 {
3134  try
3135  {
3136  TrainController->LogEvent("ClearAllMenuItemClick");
3137  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClearAllMenuItemClick");
3138  if(ClearEverything(2))
3139  {
3140  ;
3141  } // no change in action on result
3142 
3143  Level1Mode = BaseMode;
3144  SetLevel1Mode(126);
3145  Utilities->CallLogPop(1179);
3146  }
3147  catch(const Exception &e)
3148  {
3149  ErrorLog(137, e.Message);
3150  }
3151 }
3152 
3153 // ---------------------------------------------------------------------------
3154 void __fastcall TInterface::ExportTTMenuItemClick(TObject *Sender)
3155 {
3156  // no need to stop clock as can't be called when railway operating
3157  try
3158  {
3159  TrainController->LogEvent("ExportTTMenuItemClick");
3160  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTMenuItemClick");
3161  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
3162  {
3163  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
3164  Utilities->CallLogPop(1699);
3165  return;
3166  }
3167 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
3168 // the message instead, but reset here afterwards
3169  // no need to stop clock as can't select this if operating
3171  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
3172  Utilities->CallLogPop(1573);
3173  }
3174  catch(const Exception &e)
3175  {
3176  ErrorLog(138, e.Message);
3177  }
3178 }
3179 // ---------------------------------------------------------------------------
3180 // Timetable editing functions
3181 
3182 /* Note that during early development the timetable was created outside the program as a .csv file using Excel, it was only later that
3183  the editing functions within the program were developed. Much of the original structure was preserved though to avoid rewriting the
3184  code interpretation functions in TrainUnit.cpp. This is why commas are used as service event separators, and why it is necessary to
3185  convert them to CRLFs for display and back again for internal storage. It is acknowledged that all this makes the editing functions
3186  somewhat cumbersome, and, as ever, if I was starting again I wouldn't do it like that!
3187 
3188  CR & LF review:
3189  These cause problems by the way that different subroutines handle them.
3190 
3191  AnsiStrings can incorporate CRLFs, but the end of an AnsiString is marked by a '\0' character as in 'C' strings.
3192 
3193  In the fstream functions 'getline(char_type* s, streamsize n)' extracts characters from the stream and puts them in buffer 's' until
3194  (a) n-1 characters are stored + '\0' after the n-1 characters;
3195  (b) a '\n' (CRLF) character is found in the stream, in which case a '\0' is added to the buffer after the text that immediately
3196  precedes the CRLF in the stream; and
3197  (c) an eof() is found in the stream, in which case a '\0' is added to the buffer at the end of the text.
3198  Note that if no characters are stored a '\0' is still stored in position [0] of the buffer.
3199 
3200  The << operator in ofstreams, when used with a null terminated string, doesn't store the null. If it is required it has to be
3201  sent explicitly, e.g. file << '\0'. Presumably the same applies for CRLF terminated strings.
3202 
3203 */
3204 // ---------------------------------------------------------------------------
3205 
3206 void __fastcall TInterface::CreateTimetableMenuItemClick(TObject *Sender)
3207 {
3208  try
3209  {
3210  TrainController->LogEvent("CreateTimetableMenuItemClick");
3211  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CreateTimetableMenuItemClick");
3212  CreateEditTTFileName = "";
3213  TimetableEditVector.clear();
3214  TimetableEditPanel->Visible = true;
3215  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3216  HighlightPanel->Visible = false;
3217  TimetablePanel->Visible = true;
3218  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3219  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3220  OneEntryTimetableMemo->Clear();
3221  AllEntriesTTListBox->Clear();
3222  TTStartTimeBox->Text = "";
3223  AddSubMinsBox->Text = "";
3225  LocationNameComboBox->Clear();
3226  TimetableTitle = ""; // unload any loaded timetable. Added here at v2.1.0
3227  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Added here at v2.1.0
3228  SetCaption(9); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3229  TimetableChangedFlag = false;
3230  TimetableValidFlag = false;
3231  TTEntryChangedFlag = false;
3233  AZOrderButton->Caption = AnsiString("A-Z Order");
3234  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3235  CopiedEntryFlag = false;
3236  NewEntryInPreparationFlag = false;
3237  CopiedEntryStr = "";
3238  TEVPtr = 0;
3239  TTCurrentEntryPtr = 0;
3240  TTStartTimePtr = 0;
3241  TTFirstServicePtr = 0;
3242  TTLastServicePtr = 0; // all set to null to begin with
3243 
3244 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3245  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3247  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3248  {
3250  == Track->ContinuationNameMap.end())
3251  {
3252  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3253  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1038, x).ActiveTrackElementName;
3254  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3255  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3256  }
3257  }
3259  if(!(Track->ActiveTrackElementNameMap.empty()))
3260  {
3261  LocationNameComboBox->Text = "Location names";
3262 // new version at beta v0.2b
3264  ATENIT++)
3265  {
3266  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3267  // continuations as well as other track will be included - earlier version
3268  // would have excluded them
3269  }
3270 
3271 /* old version using LocationNameMultiMap, changed to use ActiveTrackElementNames to avoid including lone concourses and named non-station
3272  locations
3273  TStringList *StringList = new TStringList;
3274  StringList->Clear();//probably already empty but help file doesn't say so
3275  StringList->Sorted = false;//for now
3276  for(TTrack::TLocationNameMultiMapIterator LNMIT = Track->LocationNameMultiMap.begin(); LNMIT != Track->LocationNameMultiMap.end(); LNMIT++)
3277  {
3278  NewKey = LNMIT->first;
3279  if(OldKey != NewKey)//only add new values
3280  {
3281  if(Track->ContinuationNameMap.find(NewKey) == Track->ContinuationNameMap.end())//not a continuation
3282  {
3283  StringList->Add(NewKey);
3284  OldKey = NewKey;
3285  }
3286  }
3287  }
3288  StringList->Sort();
3289  for(int x=0;x<StringList->Count;x++)
3290  {
3291  LocationNameComboBox->Items->Add(StringList->Strings[x]);
3292  }
3293  delete StringList;
3294 */
3295  }
3296  else
3297  {
3298  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3299  }
3301  SetLevel1Mode(82);
3302  session_api_->dump(); // update session INI file //added at v2.10.0
3303  Utilities->CallLogPop(1595);
3304  }
3305  catch(const Exception &e)
3306  {
3307  ErrorLog(47, e.Message);
3308  }
3309 }
3310 
3311 // ---------------------------------------------------------------------------
3312 void __fastcall TInterface::EditTimetableMenuItemClick(TObject *Sender)
3313 /* The .ttb file contains a sequence of AnsiStrings separated by null characters. CRLFs may be embedded within the AnsiStrings,
3314  * to cause newlines when displayed. Each AnsiString corresponds to a timetable 'entry'
3315 */
3316 {
3317  try
3318  {
3319  TrainController->LogEvent("EditTimetableMenuItemClick");
3320  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EditTimetableMenuItemClick");
3321  SigImagePanel->Visible = false; // stop panel showing while waiting for name entry
3322  TimetableDialog->Filter = "Timetable file (*.ttb)|*ttb";
3323  CreateEditTTFileName = "";
3324  TimetableEditVector.clear();
3325  TimetableEditPanel->Visible = true;
3326  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3327  HighlightPanel->Visible = false;
3328  TimetablePanel->Visible = true;
3329  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3330  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3331  OneEntryTimetableMemo->Clear();
3332  AllEntriesTTListBox->Clear();
3333  TTStartTimeBox->Text = "";
3334  AddSubMinsBox->Text = "";
3336  LocationNameComboBox->Clear();
3337  TimetableTitle = ""; // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3338  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3339  SetCaption(8); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3340  TEVPtr = 0;
3342  TTFirstServicePtr = 0;
3343  TTLastServicePtr = 0; // all set to null to begin with
3344  if(TimetableDialog->Execute())
3345  {
3346  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName)) // new at v2.6.0 to retain a new directory
3347  {
3348  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3349  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3350  }
3351  CreateEditTTFileName = AnsiString(TimetableDialog->FileName);
3352  TrainController->LogEvent("EditTimetable " + CreateEditTTFileName);
3353  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary); // open in binary to examine each character
3354  if(TTBLFile.is_open())
3355  {
3356  // check doesn't contain any non-ascii characters except CR, LF & '\0', and isn't empty
3357  char c;
3358  while(!TTBLFile.eof())
3359  {
3360  TTBLFile.get(c);
3361  if((c < 32) && (c != 13) && (c != 10) && (c != '\0')) // char is signed by default so values > 127 will be caught as treated as -ve
3362  {
3363  ShowMessage("Timetable file is empty or contains non-ascii characters, codes must be between 20 and 127, or CR or LF");
3364  TTBLFile.close();
3365  Utilities->CallLogPop(1612);
3366  return;
3367  }
3368  }
3369  TTBLFile.close();
3370  }
3371  else
3372  {
3373  ShowMessage("Failed to open timetable file " + CreateEditTTFileName + ", make sure it's spelled correctly, it exists and isn't open in another application");
3374  Utilities->CallLogPop(1597);
3375  return;
3376  }
3377  // reopen again in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
3378  Delay(4, 100); // 100mSec delay between closing & re-opening file
3379  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary);
3380  if(TTBLFile.is_open())
3381  {
3382  TTBLFile.clear(); // to clear eofbit from last read
3383  TTBLFile.seekg(0); // shouldn't be needed but include for safety
3384  TimetableChangedFlag = false;
3385  TimetableValidFlag = false;
3386  TTEntryChangedFlag = false;
3388  AZOrderButton->Caption = AnsiString("A-Z Order");
3389  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3390  NewEntryInPreparationFlag = false;
3391  CopiedEntryStr = "";
3392  CopiedEntryFlag = false;
3393 // CreateEditTTFileName = TimetableDialog->FileName;
3394  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3395  {
3396  if(CreateEditTTFileName[x] == '\\')
3397  {
3398  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3399  break;
3400  }
3401  }
3402  char *TimetableEntryString = new char[10000];
3403  while(true)
3404  {
3405  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
3406  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
3407  {
3408  // may still have eof even if read a line, and
3409  // if so need to process it
3410  break;
3411  }
3412  AnsiString OneLine(TimetableEntryString);
3413  TimetableEditVector.push_back(OneLine);
3414  }
3415  TTBLFile.close();
3416  delete[]TimetableEntryString;
3417  // here with TimetableEditVector compiled
3418  }
3419  else
3420  {
3421  ShowMessage("Failed to open timetable file " + CreateEditTTFileName + ", make sure it's spelled correctly, it exists and isn't open in another application");
3422  Utilities->CallLogPop(1654);
3423  return;
3424  }
3425  }
3426  else // cancelled dialog [section prior to CallLogPop added for v1.3.2 to clear timetable screen if cancel button pressed]
3427  {
3428  CreateEditTTFileName = "";
3429 // set to null to allow a check during error file saving, if not null save the tt being edited to the file (see entry in ExitTTModeButtonClick)
3430  CreateEditTTTitle = ""; // as above
3431  Level1Mode = BaseMode;
3432  SetLevel1Mode(132);
3433  Utilities->CallLogPop(1633);
3434  return;
3435  }
3437  if(TimetableEditVector.empty())
3438  {
3440  SetLevel1Mode(89);
3441  Utilities->CallLogPop(1614);
3442  return;
3443  }
3444 // all now set where can be
3446 
3447 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3448  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3450  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3451  {
3453  == Track->ContinuationNameMap.end())
3454  {
3455  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3456  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1041, x).ActiveTrackElementName;
3457  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3458  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3459  }
3460  }
3462  if(!(Track->ActiveTrackElementNameMap.empty()))
3463  {
3464  LocationNameComboBox->Text = "Location names";
3465 // new version for beta v0.2b
3467  ATENIT++)
3468  {
3469  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3470  // continuations as well as other track will be included - earlier version
3471  // would have excluded them
3472  }
3473  }
3474  else
3475  {
3476  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3477  }
3479  SetLevel1Mode(83);
3480  session_api_->dump(); // update session INI file //added at v2.10.0
3481  Utilities->CallLogPop(1596);
3482  }
3483  catch(const Exception &e)
3484  {
3485  ErrorLog(48, e.Message);
3486  }
3487 }
3488 // ---------------------------------------------------------------------------
3489 
3490 void __fastcall TInterface::ShowHideTTButtonClick(TObject *Sender)
3491 {
3492  try
3493  {
3494  TrainController->LogEvent("ShowHideTTButtonClick");
3495  if(TimetableEditPanel->Visible)
3496  {
3497  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Show");
3498  TimetableEditPanel->Visible = false;
3499  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
3500  ShowHideTTButton->Hint = "Show the timetable editor Shift S";
3501 // InfoPanel->Visible = false; //changed at v1.3.0 to make it clearer that still in TT mode
3502  InfoPanel->Caption = "Timetable mode: editor hidden"; // as above
3503  }
3504  else
3505  {
3506  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3507  TimetableEditPanel->Visible = true;
3508  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3509  ShowHideTTButton->Hint = "Hide the timetable editor to see the railway Shift H";
3511  SetLevel1Mode(124);
3512  }
3513  }
3514  catch(const Exception &e)
3515  {
3516  ErrorLog(139, e.Message);
3517  }
3518 }
3519 // ---------------------------------------------------------------------------
3520 
3521 void __fastcall TInterface::NextTTEntryButtonClick(TObject *Sender)
3522 {
3523  try
3524  {
3525  TrainController->LogEvent("NextTTEntryButtonClick");
3526  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NextTTEntryButtonClick");
3527  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3528  {
3529  Utilities->CallLogPop(1683);
3530  return;
3531  }
3532  if(TTCurrentEntryPtr < (TimetableEditVector.end() - 1))
3533  {
3535  }
3536  TTEntryChangedFlag = false;
3537  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3538  // position changing in AllEntriesTTListBox
3540  SetLevel1Mode(85);
3541  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3542  {
3544  }
3545  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3546  {
3547  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3548  }
3549  else
3550  {
3551  AllEntriesTTListBox->TopIndex = TopPos;
3552  }
3553  Utilities->CallLogPop(1605);
3554  }
3555  catch(const Exception &e)
3556  {
3557  ErrorLog(50, e.Message);
3558  }
3559 }
3560 
3561 // ---------------------------------------------------------------------------
3562 void __fastcall TInterface::PreviousTTEntryButtonClick(TObject *Sender)
3563 {
3564  try
3565  {
3566  TrainController->LogEvent("PreviousTTEntryButtonClick");
3567  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PreviousTTEntryButtonClick");
3568  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3569  {
3570  Utilities->CallLogPop(1684);
3571  return;
3572  }
3574  {
3576  }
3577  TTEntryChangedFlag = false;
3578  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3579  // position changing in AllEntriesTTListBox
3581  SetLevel1Mode(86);
3582  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3583  {
3585  }
3586  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3587  {
3588  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3589  }
3590  else
3591  {
3592  AllEntriesTTListBox->TopIndex = TopPos;
3593  }
3594  Utilities->CallLogPop(1607);
3595  }
3596  catch(const Exception &e)
3597  {
3598  ErrorLog(51, e.Message);
3599  }
3600 }
3601 
3602 // ---------------------------------------------------------------------------
3603 void __fastcall TInterface::NewTTEntryButtonClick(TObject *Sender)
3604 {
3605  try
3606  {
3607  TrainController->LogEvent("NewTTEntryButtonClick");
3608  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewTTEntryButtonClick");
3609  OneEntryTimetableMemo->Clear();
3610  OneEntryTimetableMemo->SetFocus();
3613  SetLevel1Mode(103);
3614  Utilities->CallLogPop(1615);
3615  }
3616  catch(const Exception &e)
3617  {
3618  ErrorLog(52, e.Message);
3619  }
3620 }
3621 // ---------------------------------------------------------------------------
3622 
3623 void __fastcall TInterface::AddMinsButtonClick(TObject *Sender)
3624 {
3625  try
3626  {
3627  TrainController->LogEvent("AddMinsButtonClick");
3628  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddMinsButtonClick");
3629  bool ValidFlag = true;
3630  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3631  {
3632  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3633  {
3634  ValidFlag = false;
3635  break;
3636  }
3637  }
3638  if(ValidFlag)
3639  {
3640  if(AddSubMinsBox->Text.ToInt() == 0)
3641  {
3642  ValidFlag = false;
3643  }
3644  }
3645  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3646  {
3647  Utilities->CallLogPop(1649);
3648  return;
3649  }
3650  TDateTime DummyTime;
3651  int AddMins = AddSubMinsBox->Text.ToInt();
3652  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3653  {
3654  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3655  {
3656  if(TrainController->CheckTimeValidity(25, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3657  {
3658  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3659  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3660  Mins += AddMins;
3661  while(Mins >= 60)
3662  {
3663  Mins -= 60;
3664  Hrs++;
3665  }
3666  if(Hrs > 95)
3667  {
3668  ShowMessage("One or more times excessive, not permitted to exceed 95 hours");
3669  Utilities->CallLogPop(1650);
3670  return;
3671  }
3672  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3673  if(Mins < 10)
3674  {
3675  MinsStr = "0" + MinsStr;
3676  }
3677  if(Hrs < 10)
3678  {
3679  HrsStr = "0" + HrsStr;
3680  }
3681  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3682  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3683  NewString += HrsStr + ':' + MinsStr;
3684  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3685  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3686  }
3687  }
3688  }
3689 
3690  OneEntryTimetableMemo->HideSelection = true;
3691  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3692  OneEntryTimetableMemo->SelLength = 0;
3693  TimetableValidFlag = false;
3694  TimetableChangedFlag = true;
3695  TTEntryChangedFlag = true;
3697  SetLevel1Mode(91);
3698  Utilities->CallLogPop(1617);
3699  }
3700  catch(const Exception &e)
3701  {
3702  ErrorLog(54, e.Message);
3703  }
3704 }
3705 // ---------------------------------------------------------------------------
3706 
3707 void __fastcall TInterface::SubMinsButtonClick(TObject *Sender)
3708 {
3709  try
3710  {
3711  TrainController->LogEvent("SubMinsButtonClick");
3712  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SubMinsButtonClick");
3713  bool ValidFlag = true;
3714  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3715  {
3716  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3717  {
3718  ValidFlag = false;
3719  break;
3720  }
3721  }
3722  if(ValidFlag)
3723  {
3724  if(AddSubMinsBox->Text.ToInt() == 0)
3725  {
3726  ValidFlag = false;
3727  }
3728  }
3729  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3730  {
3731  Utilities->CallLogPop(1659);
3732  return;
3733  }
3734  TDateTime DummyTime;
3735  int SubMins = AddSubMinsBox->Text.ToInt();
3736  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3737  {
3738  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3739  {
3740  if(TrainController->CheckTimeValidity(28, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3741  {
3742  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3743  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3744  Mins -= SubMins;
3745  while(Mins < 0)
3746  {
3747  Mins += 60;
3748  Hrs--;
3749  }
3750  if(Hrs < 0)
3751  {
3752  ShowMessage("One or more times are now before 00:00, this is not permitted");
3753  Utilities->CallLogPop(1660);
3754  return;
3755  }
3756  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3757  if(Mins < 10)
3758  {
3759  MinsStr = "0" + MinsStr;
3760  }
3761  if(Hrs < 10)
3762  {
3763  HrsStr = "0" + HrsStr;
3764  }
3765  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3766  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3767  NewString += HrsStr + ':' + MinsStr;
3768  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3769  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3770  }
3771  }
3772  }
3773  OneEntryTimetableMemo->HideSelection = true;
3774  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3775  OneEntryTimetableMemo->SelLength = 0;
3776  TimetableValidFlag = false;
3777  TimetableChangedFlag = true;
3778  TTEntryChangedFlag = true;
3780  SetLevel1Mode(92);
3781  Utilities->CallLogPop(1618);
3782  }
3783  catch(const Exception &e)
3784  {
3785  ErrorLog(55, e.Message);
3786  }
3787 }
3788 // ---------------------------------------------------------------------------
3789 
3790 void __fastcall TInterface::CopyTTEntryButtonClick(TObject *Sender)
3791 {
3792  try
3793  {
3794  TrainController->LogEvent("CopyTTEntryButtonClick");
3795  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyTTEntryButtonClick");
3796  if(TTCurrentEntryPtr == 0)
3797  {
3798  Utilities->CallLogPop(1636);
3799  return;
3800  }
3802  CopiedEntryFlag = true;
3803  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3804  // position changing in AllEntriesTTListBox
3806  SetLevel1Mode(93);
3807  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3808  {
3810  }
3811  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3812  {
3813  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3814  }
3815  else
3816  {
3817  AllEntriesTTListBox->TopIndex = TopPos;
3818  }
3819  Utilities->CallLogPop(1619);
3820  }
3821  catch(const Exception &e)
3822  {
3823  ErrorLog(56, e.Message);
3824  }
3825 }
3826 // ---------------------------------------------------------------------------
3827 
3828 void __fastcall TInterface::CutTTEntryButtonClick(TObject *Sender)
3829 {
3830  try
3831  {
3832  TrainController->LogEvent("CutTTEntryButtonClick");
3833  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutTTEntryButtonClick");
3834  if(TTCurrentEntryPtr == 0) // || (*TTCurrentEntryPtr == ""))//safeguard
3835  {
3836  Utilities->CallLogPop(1674);
3837  return;
3838  }
3840  CopiedEntryFlag = true;
3841  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3842  // so use the position in the vector
3844 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3845 // pick up the start time if there is one
3846  TimetableChangedFlag = true;
3847  TimetableValidFlag = false;
3848  TTEntryChangedFlag = false;
3849  TEVPtr = 0;
3851  TTFirstServicePtr = 0;
3852  TTLastServicePtr = 0; // all set to null to begin with
3853  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3854  // position changing in AllEntriesTTListBox
3855  AllEntriesTTListBox->Clear();
3857  if(TimetableEditVector.empty())
3858  {
3860  SetLevel1Mode(109);
3861  Utilities->CallLogPop(1777);
3862  return;
3863  }
3864 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one //was 'after', changed at v2.5.0
3865 // but vector pointers unreliable after an erase, so use the position in the vector
3866  if(OldVectorPos == 0)
3867  {
3869  }
3870  else
3871  {
3872  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3873  }
3874  if(TTCurrentEntryPtr == 0)
3875  {
3876  OneEntryTimetableMemo->Clear();
3877  }
3879  SetLevel1Mode(115);
3880  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3881  {
3883  }
3884  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3885  {
3886  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3887  }
3888  else
3889  {
3890  AllEntriesTTListBox->TopIndex = TopPos;
3891  }
3892  Utilities->CallLogPop(1676);
3893  }
3894  catch(const Exception &e)
3895  {
3896  ErrorLog(111, e.Message);
3897  }
3898 }
3899 
3900 // ---------------------------------------------------------------------------
3901 void __fastcall TInterface::PasteTTEntryButtonClick(TObject *Sender)
3902 {
3903  try
3904  {
3905  TrainController->LogEvent("PasteTTEntryButtonClick");
3906  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteTTEntryButtonClick");
3907  if(TTCurrentEntryPtr == 0) // || (CopiedEntryStr == "")) allow blank copies
3908  {
3909  Utilities->CallLogPop(1637);
3910  return;
3911  }
3912  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3913  TimetableEditVector.insert(TTCurrentEntryPtr + 1, CopiedEntryStr); // inserts before the indicated pointer position, i.e. immediately
3914  // after the current Entry - may be at the end
3915  TimetableChangedFlag = true;
3916  TimetableValidFlag = false;
3917  TTEntryChangedFlag = false;
3918  TEVPtr = 0;
3920  TTFirstServicePtr = 0;
3921  TTLastServicePtr = 0; // all set to null to begin with
3922  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3923  // position changing in AllEntriesTTListBox
3924  AllEntriesTTListBox->Clear();
3926  if(TimetableEditVector.empty())
3927  {
3929  SetLevel1Mode(110);
3930  Utilities->CallLogPop(1778);
3931  return;
3932  }
3933 // restore TTCurrentEntryPtr
3934  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3935  TTCurrentEntryPtr++; // advance the pointer to the pasted entry
3936 // CopiedEntryStr = "";//revert to null - no, allow multiple copies
3938  SetLevel1Mode(94);
3939  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3940  {
3942  }
3943  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3944  {
3945  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3946  }
3947  else
3948  {
3949  AllEntriesTTListBox->TopIndex = TopPos;
3950  }
3951  Utilities->CallLogPop(1620);
3952  }
3953  catch(const Exception &e)
3954  {
3955  ErrorLog(57, e.Message);
3956  }
3957 }
3958 // ---------------------------------------------------------------------------
3959 
3960 void __fastcall TInterface::DeleteTTEntryButtonClick(TObject *Sender)
3961 {
3962  try
3963  {
3964  TrainController->LogEvent("DeleteTTEntryButtonClick");
3965  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteTTEntryButtonClick");
3966  if(TTCurrentEntryPtr == 0)
3967  {
3968  Utilities->CallLogPop(1645);
3969  return;
3970  }
3971  UnicodeString MessageStr = "Are you sure this entry should be deleted?";
3972  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
3973  if(button == IDNO)
3974  {
3975  Utilities->CallLogPop(1663);
3976  return;
3977  }
3978  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3979  // so use the position in the vector
3981 
3982 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3983 // pick up the start time if there is one
3984  TimetableChangedFlag = true;
3985  TimetableValidFlag = false;
3986  TTEntryChangedFlag = false;
3987  TEVPtr = 0;
3989  TTFirstServicePtr = 0;
3990  TTLastServicePtr = 0; // all set to null to begin with
3991  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3992  // position changing in AllEntriesTTListBox
3993  AllEntriesTTListBox->Clear();
3995  if(TimetableEditVector.empty())
3996  {
3998  SetLevel1Mode(111);
3999  Utilities->CallLogPop(1779);
4000  return;
4001  }
4002 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one
4003 // but vector pointers unreliable after an erase, so use the position in the vector
4004  if(OldVectorPos == 0)
4005  {
4007  }
4008  else
4009  {
4010  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
4011  }
4012  if(TTCurrentEntryPtr == 0)
4013  {
4014  OneEntryTimetableMemo->Clear();
4015  }
4017  SetLevel1Mode(95);
4018  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4019  {
4021  }
4022  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4023  {
4024  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4025  }
4026  else
4027  {
4028  AllEntriesTTListBox->TopIndex = TopPos;
4029  }
4030  Utilities->CallLogPop(1621);
4031  }
4032  catch(const Exception &e)
4033  {
4034  ErrorLog(58, e.Message);
4035  }
4036 }
4037 // ---------------------------------------------------------------------------
4038 
4039 void __fastcall TInterface::SaveTTEntryButtonClick(TObject *Sender)
4040 {
4041  try
4042  {
4043  TrainController->LogEvent("SaveTTEntryButtonClick");
4044  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTEntryButtonClick");
4045 /* allow blank lines to be saved
4046  AnsiString ContentStr = OneEntryTimetableMemo->Text;
4047  if((ContentStr == "\r\n") || (ContentStr == "\n") || (ContentStr == ""))
4048  {
4049  Utilities->CallLogPop(1679);
4050  return;
4051  }
4052 */
4053  AnsiString TempStr = "";
4054  bool ActiveLine = false;
4055  if(TTCurrentEntryPtr > 0)
4056  {
4057  if(*TTCurrentEntryPtr != "")
4058  {
4060  {
4061  ActiveLine = true;
4062  // need to add commas after each line in OneEntryTimetableMemo exept the last, where have '\0'
4063  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
4064  {
4065  for(int y = 1; y <= OneEntryTimetableMemo->Lines->Strings[x].Length(); y++)
4066  {
4067  TempStr += OneEntryTimetableMemo->Lines->Strings[x][y];
4068  }
4069  if(x < (OneEntryTimetableMemo->Lines->Count - 1))
4070  {
4071  TempStr += ',';
4072  }
4073  // No need to add a '\n' as a '\0' is added automatically as a string delimiter. If add '\n' then it is treated as a blank line and
4074  // ends the timetable
4075  }
4076  // strip any excess commas from the end
4077  if(TempStr != "")
4078  {
4079  while(TempStr[TempStr.Length()] == ',')
4080  {
4081  TempStr = TempStr.SubString(1, TempStr.Length() - 1);
4082  if(TempStr == "")
4083  {
4084  break;
4085  }
4086  }
4087  }
4088  }
4089  }
4090  }
4091  if(!ActiveLine)
4092  {
4093  TempStr = OneEntryTimetableMemo->Text; // Note that if the entry was intended as a service but goes in as plain text because
4094  // the service & entry pointers aren't yet set, then CRLFs will be converted to commas in
4095  // CompileAllEntriesMemoAndSetPointers if it appears after the start time
4096  // and before a blank line or end of file, so the syntax check will work OK
4097  }
4098  if(AZOrderButton->Caption == AnsiString("Original Order"))
4099  {
4101  }
4102  TimetableValidFlag = false;
4103  TimetableChangedFlag = true;
4104  TTEntryChangedFlag = false;
4105  int TopPos;
4106  if(TTCurrentEntryPtr == 0)
4107  {
4109  }
4111  {
4112  (*TTCurrentEntryPtr) = TempStr;
4113  // need to reset the AllEntriesTTListBox in case the headcode has changed
4114  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4115  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4116  // position changing in AllEntriesTTListBox
4117  AllEntriesTTListBox->Clear();
4119  if(TimetableEditVector.empty())
4120  {
4122  SetLevel1Mode(112);
4123  Utilities->CallLogPop(1780);
4124  return;
4125  }
4126  // restore TTCurrentEntryPtr
4127  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4128  }
4129  else
4130  {
4131  NewEntryInPreparationFlag = false;
4132  if(TTCurrentEntryPtr != 0)
4133  {
4134  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4135  TimetableEditVector.insert(TTCurrentEntryPtr + 1, TempStr); // inserts before the indicated pointer position, which may be at the end
4136  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4138  }
4139  else
4140  {
4141  TimetableEditVector.insert(TimetableEditVector.end(), TempStr); // inserts before the indicated pointer position
4143  }
4144  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the current position
4145  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4146  // position changing in AllEntriesTTListBox
4147  AllEntriesTTListBox->Clear();
4149  if(TimetableEditVector.empty())
4150  {
4152  SetLevel1Mode(113);
4153  Utilities->CallLogPop(1781);
4154  return;
4155  }
4156 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4157  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4158  {
4160  }
4161  else
4162  {
4163  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4164  }
4165  }
4167  SetLevel1Mode(96);
4168  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4169  {
4171  }
4172  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4173  {
4174  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4175  }
4176  else
4177  {
4178  AllEntriesTTListBox->TopIndex = TopPos;
4179  }
4180  Utilities->CallLogPop(1622);
4181  }
4182  catch(const Exception &e)
4183  {
4184  ErrorLog(59, e.Message);
4185  }
4186 }
4187 // ---------------------------------------------------------------------------
4188 
4189 void __fastcall TInterface::SaveTTButtonClick(TObject *Sender)
4190 {
4191  try
4192  {
4193  TrainController->LogEvent("SaveTTButtonClick");
4194  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTButtonClick");
4195  if(TimetableEditVector.empty())
4196  {
4197  ShowMessage("Timetable is empty, can't save an empty timetable");
4198  Utilities->CallLogPop(1685);
4199  return;
4200  }
4201  std::ofstream TTBLFile;
4202  if(CreateEditTTFileName != "")
4203  {
4204  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4205  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4206  }
4207  else
4208  {
4209  if(SaveTTDialog->Execute())
4210  {
4211  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName)) // new at v2.6.0 to retain a new directory
4212  {
4213  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4214  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4215  }
4216  CreateEditTTFileName = AnsiString(SaveTTDialog->FileName);
4217  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
4218  {
4219  if(CreateEditTTFileName[x] == '\\')
4220  {
4221  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4222  break;
4223  }
4224  }
4225  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4226  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4227  }
4228  else // cancelled dialog
4229  {
4231  SetLevel1Mode(137);
4232  Utilities->CallLogPop(2205);
4233  return;
4234  }
4235  }
4236  if(TTBLFile.is_open())
4237  {
4238  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4239  {
4240  TTBLFile << (*TEVPtr).c_str() << '\0';
4241  }
4242  TimetableChangedFlag = false;
4243  TTBLFile.close();
4244  }
4245  else
4246  {
4247  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4248  }
4250  SetLevel1Mode(97);
4251  Utilities->CallLogPop(1623);
4252  }
4253  catch(const Exception &e)
4254  {
4255  ErrorLog(60, e.Message);
4256  }
4257 }
4258 // ---------------------------------------------------------------------------
4259 
4260 void __fastcall TInterface::SaveTTAsButtonClick(TObject *Sender)
4261 {
4262  try
4263  {
4264  TrainController->LogEvent("SaveTTAsButtonClick");
4265  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTAsButtonClick");
4266  if(TimetableEditVector.empty())
4267  {
4268  ShowMessage("Timetable is empty, can't save an empty timetable");
4269  Utilities->CallLogPop(1686);
4270  return;
4271  }
4272  std::ofstream TTBLFile;
4273  if(SaveTTDialog->Execute())
4274  {
4275  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName)) // new at v2.6.0 to retain a new directory
4276  {
4277  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4278  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4279  }
4280  CreateEditTTFileName = SaveTTDialog->FileName;
4281  for(int x = SaveTTDialog->FileName.Length(); x > 0; x--)
4282  {
4283  if(SaveTTDialog->FileName[x] == '\\')
4284  {
4285  CreateEditTTTitle = SaveTTDialog->FileName.SubString(x + 1, SaveTTDialog->FileName.Length() - x - 4);
4286  break;
4287  }
4288  }
4289  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4290  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4291  }
4292  else // cancelled dialog
4293  {
4295  SetLevel1Mode(138);
4296  Utilities->CallLogPop(2206);
4297  return;
4298  }
4299  if(TTBLFile.is_open())
4300  {
4301  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4302  {
4303  TTBLFile << (*TEVPtr).c_str() << '\0';
4304  }
4305  TimetableChangedFlag = false;
4306  TTBLFile.close();
4307  }
4308  else
4309  {
4310  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4311  }
4313  SetLevel1Mode(117);
4314  Utilities->CallLogPop(1667);
4315  }
4316  catch(const Exception &e)
4317  {
4318  ErrorLog(108, e.Message);
4319  }
4320 }
4321 // ---------------------------------------------------------------------------
4322 
4323 void __fastcall TInterface::TTServiceSyntaxCheckButtonClick(TObject *Sender)
4324 {
4325  try
4326  {
4327  TrainController->LogEvent("TTServiceSyntaxCheckButtonClick");
4328  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTServiceSyntaxCheckButtonClick");
4329  int Count = 1; // anything > 0 OK as if 0 still seeking a start time
4330  bool EndOfFile = false;
4331  bool FinalCallFalse = false;
4332  bool GiveMessagesTrue = true;
4333  bool CheckLocationsExistInRailway = false;
4334  if(RlyFile)
4335  {
4336  CheckLocationsExistInRailway = true;
4337  }
4338 // TrainController->AnyHeadCodeValid = true; //don't fail here because of an unrestricted headcode, if no good will find when validate (dropped at v0.6b)
4339  if(TrainController->ProcessOneTimetableLine(2, Count, *TTCurrentEntryPtr, EndOfFile, FinalCallFalse, GiveMessagesTrue, CheckLocationsExistInRailway))
4340  // return true for success
4341  {
4342  ShowMessage(
4343  "The basic syntax seems OK but this check is very limited. Other aspects can only be checked by validating the whole timetable with the appropriate railway (.rly) loaded");
4344  }
4346  SetLevel1Mode(98);
4347  Utilities->CallLogPop(1624);
4348  }
4349  catch(const Exception &e)
4350  {
4351  ErrorLog(61, e.Message);
4352  }
4353 }
4354 // ---------------------------------------------------------------------------
4355 
4356 void __fastcall TInterface::ValidateTimetableButtonClick(TObject *Sender)
4357 {
4358  try
4359  {
4360  TrainController->LogEvent("ValidateTimetableButtonClick");
4361  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ValidateTimetableButtonClick");
4362  // reset all message flags, stops them being given twice new at v2.4.0
4363  TrainController->SSHigh = false;
4364  TrainController->MRSHigh = false;
4365  TrainController->MRSLow = false;
4366  TrainController->MassHigh = false;
4367  TrainController->BFHigh = false;
4368  TrainController->BFLow = false;
4369  TrainController->PwrHigh = false;
4370  TrainController->SigSHigh = false;
4371  TrainController->SigSLow = false;
4372  if(CreateEditTTFileName == "")
4373  {
4374  Utilities->CallLogPop(1664);
4375  return;
4376  }
4377  bool CheckLocationsExistInRailwayTrue = true;
4378  if(TrainController->TimetableIntegrityCheck(2, CreateEditTTFileName.c_str(), true, CheckLocationsExistInRailwayTrue)) // messages = true
4379  {
4380  Screen->Cursor = TCursor(-11); // Hourglass;
4381  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4382  if(TTBLFile.is_open())
4383  {
4384  if(BuildTrainDataVectorForValidateFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue)) // messages = true
4385  {
4386  if(!TwoLocationNamePanel->Visible) //added at v2.9.1. If this visible don't override it with another message.
4387  {
4388  ShowMessage("Timetable integrity OK");
4389  TimetableValidFlag = true;
4390  }
4391 // TrainController->TrainDataVector.clear(); keep this so can export a formatted tt
4392  }
4393  }
4394  else
4395  {
4396  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
4397  }
4398  Screen->Cursor = TCursor(-2); // Arrow
4399  } // if(TimetableIntegrityCheck
4400  else
4401  {
4402 // ShowMessage("Timetable preliminary integrity check failed"); dropped in v2.4.0 as messages given in all called functions
4403  }
4405  SetLevel1Mode(99);
4406  Utilities->CallLogPop(1625);
4407  }
4408  catch(const Exception &e)
4409  {
4410  ErrorLog(62, e.Message);
4411  }
4412 }
4413 
4414 // ---------------------------------------------------------------------------
4415 void __fastcall TInterface::MoveTTEntryUpButtonClick(TObject *Sender)
4416 {
4417  try
4418  {
4419  TrainController->LogEvent("MoveTTEntryUpButtonClick");
4420  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryUpButtonClick");
4421  if(TTCurrentEntryPtr == 0)
4422  {
4423  Utilities->CallLogPop(1634);
4424  return;
4425  }
4426  if(TTCurrentEntryPtr < (TimetableEditVector.begin() + 1)) // shouldn't reach here but return if do
4427  {
4428  Utilities->CallLogPop(1632);
4429  return;
4430  }
4431  TEVPtr = TTCurrentEntryPtr - 1; // find earlier Entry
4432  AnsiString TempStr = *TEVPtr;
4434  *TTCurrentEntryPtr = TempStr;
4436  TimetableChangedFlag = true;
4437  TimetableValidFlag = false;
4438 
4439 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4440  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4441  // position changing in AllEntriesTTListBox
4442  AllEntriesTTListBox->Clear();
4443  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4445 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4446  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4447  {
4449  }
4450  else
4451  {
4452  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4453  }
4455  SetLevel1Mode(100);
4456  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4457  {
4459  }
4460  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4461  {
4462  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4463  }
4464  else
4465  {
4466  AllEntriesTTListBox->TopIndex = TopPos;
4467  }
4468  Utilities->CallLogPop(1626);
4469  }
4470  catch(const Exception &e)
4471  {
4472  ErrorLog(63, e.Message);
4473  }
4474 }
4475 // ---------------------------------------------------------------------------
4476 
4477 void __fastcall TInterface::MoveTTEntryDownButtonClick(TObject *Sender)
4478 {
4479  try
4480  {
4481  TrainController->LogEvent("MoveTTEntryDownButtonClick");
4482  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryDownButtonClick");
4483  if(TTCurrentEntryPtr == 0)
4484  {
4485  Utilities->CallLogPop(1635);
4486  return;
4487  }
4488  if(TTCurrentEntryPtr >= (TimetableEditVector.end() - 1)) // shouldn't reach here but return if do
4489  {
4490  Utilities->CallLogPop(1678);
4491  return;
4492  }
4493  TEVPtr = TTCurrentEntryPtr + 1; // find later Entry
4494  AnsiString TempStr = *TEVPtr;
4496  *TTCurrentEntryPtr = TempStr;
4498  TimetableChangedFlag = true;
4499  TimetableValidFlag = false;
4500 
4501 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4502  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4503  // position changing in AllEntriesTTListBox
4504  AllEntriesTTListBox->Clear();
4505  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4507 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4508  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4509  {
4511  }
4512  else
4513  {
4514  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4515  }
4517  SetLevel1Mode(101);
4518  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4519  {
4521  }
4522  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4523  {
4524  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4525  }
4526  else
4527  {
4528  AllEntriesTTListBox->TopIndex = TopPos;
4529  }
4530  Utilities->CallLogPop(1627);
4531  }
4532  catch(const Exception &e)
4533  {
4534  ErrorLog(64, e.Message);
4535  }
4536 }
4537 
4538 // ---------------------------------------------------------------------------
4539 void __fastcall TInterface::CancelTTEntryButtonClick(TObject *Sender)
4540 {
4541  try
4542  {
4543  TrainController->LogEvent("CancelTTActionButtonClick");
4544  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelTTActionButtonClick");
4545  TTEntryChangedFlag = false;
4547  {
4548  NewEntryInPreparationFlag = false;
4549  OneEntryTimetableMemo->Clear();
4550  }
4551  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4552  // position changing in AllEntriesTTListBox
4554  SetLevel1Mode(102);
4555  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4556  {
4558  }
4559  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4560  {
4561  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4562  }
4563  else
4564  {
4565  AllEntriesTTListBox->TopIndex = TopPos;
4566  }
4567  Utilities->CallLogPop(1630);
4568  }
4569  catch(const Exception &e)
4570  {
4571  ErrorLog(102, e.Message);
4572  }
4573 }
4574 
4575 // ---------------------------------------------------------------------------
4576 void __fastcall TInterface::RestoreTTButtonClick(TObject *Sender)
4577 {
4578  try
4579  {
4580  TrainController->LogEvent("RestoreTTButtonClick");
4581  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreTTButtonClick");
4583  {
4584  UnicodeString MessageStr = "All changes to the timetable will be lost - proceed?";
4585  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4586  if(button == IDNO)
4587  {
4588  Utilities->CallLogPop(1651);
4589  return;
4590  }
4591  }
4592  // repeat from EditTimetableMenuItemClick, but no need to check for non-ascii characters
4593  // open in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
4594  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4595  if(TTBLFile.is_open())
4596  {
4597  TimetableChangedFlag = false;
4598  TimetableValidFlag = false;
4599  TTEntryChangedFlag = false;
4600  NewEntryInPreparationFlag = false;
4601  CopiedEntryFlag = false;
4602  CopiedEntryStr = "";
4603  TimetableEditVector.clear();
4604  OneEntryTimetableMemo->Clear();
4605  AllEntriesTTListBox->Clear();
4606  TTStartTimeBox->Text = "";
4607  AddSubMinsBox->Text = "";
4608  TEVPtr = 0;
4610  TTFirstServicePtr = 0;
4611  TTLastServicePtr = 0; // all set to null to begin with
4612  char *TimetableEntryString = new char[10000];
4613  while(true)
4614  {
4615  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
4616  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
4617  {
4618  // may still have eof even if read a line, and
4619  // if so need to process it
4620  break;
4621  }
4622  AnsiString OneLine(TimetableEntryString);
4623  TimetableEditVector.push_back(OneLine);
4624  }
4625  TTBLFile.close();
4626  delete[]TimetableEntryString;
4627  // here with TimetableEditVector compiled
4628  }
4629  else
4630  {
4631  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
4632  Utilities->CallLogPop(1655);
4633  return;
4634  }
4636  if(TimetableEditVector.empty())
4637  {
4639  SetLevel1Mode(114);
4640  Utilities->CallLogPop(1782);
4641  return;
4642  }
4643 // all now set where can be
4645 // end of repeat from EditTimetableMenuItemClick
4646 
4648  SetLevel1Mode(104);
4649  Utilities->CallLogPop(1652);
4650  }
4651  catch(const Exception &e)
4652  {
4653  ErrorLog(104, e.Message);
4654  }
4655 }
4656 
4657 // ---------------------------------------------------------------------------
4658 void __fastcall TInterface::ExportTTButtonClick(TObject *Sender)
4659 {
4660  try
4661  {
4662  TrainController->LogEvent("ExportTTButtonClick");
4663  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTButtonClick");
4664  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
4665  {
4666  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
4667  Utilities->CallLogPop(1698);
4668  return;
4669  }
4670 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
4671 // the message instead, but reset here afterwards
4672  AnsiString TTTitle;
4674  {
4675  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
4676  {
4677  if(CreateEditTTFileName[x] == '\\')
4678  {
4679  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4680  break;
4681  }
4682  }
4684  }
4685  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
4687  SetLevel1Mode(116);
4688  Utilities->CallLogPop(1662);
4689  }
4690  catch(const Exception &e)
4691  {
4692  ErrorLog(107, e.Message);
4693  }
4694 }
4695 
4696 // ---------------------------------------------------------------------------
4697 void __fastcall TInterface::TTTextButtonClick(TObject *Sender)
4698 {
4699  try
4700  {
4701  TrainController->LogEvent("TTTextButtonClick");
4702  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTTextButtonClick");
4703 /*
4704  if(TTStartTimePtr == 0)
4705  {
4706  OneEntryTimetableMemo->Clear();
4707  TTStartTimeBox->SetFocus();
4708  Utilities->CallLogPop(1673);
4709  return;
4710  }
4711 */
4712  int SelPos = OneEntryTimetableMemo->SelStart;
4713  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4714  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4715  OneEntryTimetableMemo->Text = FirstPart + ((TButton*)Sender)->Caption + LastPart;
4716  OneEntryTimetableMemo->SelStart = SelPos + ((TButton*)Sender)->Caption.Length();
4717  TTEntryChangedFlag = true;
4718  OneEntryTimetableMemo->SetFocus();
4720  SetLevel1Mode(119);
4721  Utilities->CallLogPop(1672);
4722  }
4723  catch(const Exception &e)
4724  {
4725  ErrorLog(110, e.Message);
4726  }
4727 }
4728 
4729 // ---------------------------------------------------------------------------
4730 void __fastcall TInterface::ExitTTModeButtonClick(TObject *Sender)
4731 {
4732  try
4733  {
4734  TrainController->LogEvent("ExitTTCreateEditButtonClick");
4735  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTTCreateEditButtonClick");
4737  {
4738  UnicodeString MessageStr = "The timetable has changed.\n\nAre you sure you want to exit without saving it?";
4739  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4740  if(button == IDNO)
4741  {
4742  Utilities->CallLogPop(1603);
4743  return;
4744  }
4745  }
4746  TimetableChangedFlag = false;
4747  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
4748  // added for Beta v0.2b
4749  CreateEditTTTitle = ""; // as above
4750  ConflictPanel->Visible = false;
4751  Level1Mode = BaseMode;
4752  SetLevel1Mode(84);
4753  Utilities->CallLogPop(1606);
4754  }
4755  catch(const Exception &e)
4756  {
4757  ErrorLog(49, e.Message);
4758  }
4759 }
4760 
4761 // ---------------------------------------------------------------------------
4762 void __fastcall TInterface::LocationNameComboBoxClick(TObject *Sender)
4763 {
4764  try
4765  {
4766  TrainController->LogEvent("LocationNameComboBoxClick");
4767  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxClick");
4768  if(TTStartTimePtr != 0)
4769  {
4770  LocationNameComboBox->SelectAll();
4771  int SelPos = OneEntryTimetableMemo->SelStart;
4772  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4773  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4774  OneEntryTimetableMemo->Text = FirstPart + LocationNameComboBox->SelText + LastPart;
4775  OneEntryTimetableMemo->SelStart = SelPos + LocationNameComboBox->SelText.Length();
4776  TTEntryChangedFlag = true;
4777  OneEntryTimetableMemo->SetFocus();
4779  SetLevel1Mode(118);
4780  }
4781  Utilities->CallLogPop(1669);
4782  }
4783  catch(const Exception &e)
4784  {
4785  ErrorLog(109, e.Message);
4786  }
4787 }
4788 
4789 // ---------------------------------------------------------------------------
4790 void __fastcall TInterface::OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4791 {
4792  try
4793  {
4794 // TrainController->LogEvent("OneEntryTimetableMemoKeyUp"); drop this - too many entries
4795  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OneEntryTimetableMemoKeyUp");
4797  {
4798  Utilities->CallLogPop(1716);
4799  return;
4800  }
4801  TimetableChangedFlag = true;
4802  TTEntryChangedFlag = true;
4803  TimetableValidFlag = false;
4805  SetLevel1Mode(127);
4806  Utilities->CallLogPop(1629);
4807  }
4808  catch(const Exception &e)
4809  {
4810  ErrorLog(66, e.Message);
4811  }
4812 }
4813 
4814 // ---------------------------------------------------------------------------
4815 void __fastcall TInterface::AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4816 {
4817 // forces a recheck for whether addmins/submins buttons should be enabled
4818  try
4819  {
4820  TrainController->LogEvent("AddSubMinsBoxKeyUp");
4821  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddSubMinsBoxKeyUp");
4823  SetLevel1Mode(108);
4824  Utilities->CallLogPop(1658);
4825  }
4826  catch(const Exception &e)
4827  {
4828  ErrorLog(106, e.Message);
4829  }
4830 }
4831 
4832 // ---------------------------------------------------------------------------
4833 void __fastcall TInterface::LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4834 {
4835  try
4836  {
4837  TrainController->LogEvent("LocationNameComboBoxKeyUp");
4838  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxKeyUp");
4839  if(!Track->LocationNameMultiMap.empty())
4840  {
4841  LocationNameComboBox->Text = "Location names";
4842  }
4843  else
4844  {
4845  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
4846  }
4847  Utilities->CallLogPop(1677);
4848  }
4849  catch(const Exception &e)
4850  {
4851  ErrorLog(112, e.Message);
4852  }
4853 }
4854 
4855 // ---------------------------------------------------------------------------
4856 
4857 void __fastcall TInterface::AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4858 {
4859 // Select the item pointed to unless a 'save entry' is pending in which case ignore
4860  try
4861  {
4862  TrainController->LogEvent("AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4863  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4864  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
4865  {
4866  Utilities->CallLogPop(1687);
4867  return;
4868  }
4869  if(TTEntryChangedFlag || NewEntryInPreparationFlag) // if a save/cancel pending don't permit anything else
4870  {
4871  Utilities->CallLogPop(1688);
4872  return;
4873  }
4874  // find item required - 13 pixels per line of text
4875  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4876  // position changing in AllEntriesTTListBox
4877  if((TopPos + (Y / 13)) >= AllEntriesTTListBox->Items->Count)
4878  {
4880  }
4881  else
4882  {
4883  TTCurrentEntryPtr = TimetableEditVector.begin() + (Y / 13) + TopPos;
4884  }
4885  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4887 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4888  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4889  {
4891  }
4892  else
4893  {
4894  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4895  }
4897  SetLevel1Mode(120);
4898  AllEntriesTTListBox->TopIndex = TopPos; // reset it after SetLevel1Mode to prevent the scroll position changing
4899  Utilities->CallLogPop(1648);
4900  }
4901  catch(const Exception &e)
4902  {
4903  ErrorLog(103, e.Message);
4904  }
4905 }
4906 
4907 // ---------------------------------------------------------------------------
4908 
4909 void __fastcall TInterface::OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4910 {
4911 // Mouseup rather than Mousedown so shows floating label when over selected train
4912  try
4913  {
4914  TrainController->LogEvent("OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y) + "," + AnsiString(Button)); // button may be right or left
4915  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4916  int ScreenPosH, ScreenPosV;
4917  if(Track->RouteFlashFlag || Track->PointFlashFlag) // no action
4918  {
4919  Utilities->CallLogPop(2087);
4920  return;
4921  }
4923  {
4924  Utilities->CallLogPop(2088);
4925  return;
4926  }
4927  int HPos, VPos, TrainID = -1, TrackVectorPosition = -1;
4928  if(!GetTrainIDOrContinuationPosition(0, X, Y, TrainID, TrackVectorPosition))
4929  {
4930  OAListBoxRightMouseButtonDown = false; // so resets when button over blank area
4931  Utilities->CallLogPop(2260);
4932  return;
4933  }
4934  if(Button == mbLeft) // added at v2.7.0 to keep right button for train information
4935  {
4936  HPos = (Track->TrackElementAt(926, TrackVectorPosition).HLoc * 16);
4937  VPos = (Track->TrackElementAt(927, TrackVectorPosition).VLoc * 16);
4938 //these checks added at v2.11.0 to centre train on display if it's under either of these panels
4939 //HPos relative to MainScreen, but panels relative to Interface form
4940  bool ElementUnderOAPanel = false;
4941  if(OperatorActionPanel->Visible)
4942  { //4 added because train position 4 right and below element position
4943  if(((HPos - (Display->DisplayOffsetH * 16) + MainScreen->Left + 4) >= OperatorActionPanel->Left) &&
4944  ((HPos - (Display->DisplayOffsetH * 16) + MainScreen->Left + 4) <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
4945  ((VPos - (Display->DisplayOffsetV * 16) + MainScreen->Top + 4) >= OperatorActionPanel->Top) &&
4946  ((VPos - (Display->DisplayOffsetV * 16) + MainScreen->Top + 4) <= (OperatorActionPanel->Top + OperatorActionPanel->Height)))
4947  {
4948  ElementUnderOAPanel = true;
4949  }
4950  }
4951  bool ElementUnderPerformancePanel = false;
4952  if(PerformancePanel->Visible)
4953  {
4954  if(((HPos - (Display->DisplayOffsetH * 16) + MainScreen->Left + 4) >= PerformancePanel->Left) &&
4955  ((HPos - (Display->DisplayOffsetH * 16) + MainScreen->Left + 4) <= (PerformancePanel->Left + PerformancePanel->Width)) &&
4956  ((VPos - (Display->DisplayOffsetV * 16) + MainScreen->Top + 4) >= PerformancePanel->Top) &&
4957  ((VPos - (Display->DisplayOffsetV * 16) + MainScreen->Top + 4) <= (PerformancePanel->Top + PerformancePanel->Height)))
4958  {
4959  ElementUnderPerformancePanel = true;
4960  }
4961  }
4962  //if train is already shown on the screen then don't move the viewpoint, if not then display it in the centre
4963  //added at v2.10.0
4964  if(((HPos - (Display->DisplayOffsetH * 16)) >= 0) && ((HPos - (Display->DisplayOffsetH * 16)) < MainScreen->Width) &&
4965  ((VPos - (Display->DisplayOffsetV * 16)) >= 0) && ((VPos - (Display->DisplayOffsetV * 16)) < MainScreen->Height) &&
4966  !ElementUnderPerformancePanel && !ElementUnderOAPanel) // element on screen & not hidden behind a panel
4967  {
4968  ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
4969  ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
4970  }
4971  else
4972  {
4973  // set the offsets to display HPos & VPos in the centre of the screen
4974  Display->DisplayOffsetH = (HPos - MainScreen->Width / 2) / 16; // ScreenPosH = HPos - (DisplayOffsetH * 16)
4975  Display->DisplayOffsetV = (VPos - MainScreen->Height / 2) / 16;
4976  ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
4977  ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
4978  }
4979  if(Display->ZoomOutFlag) // panel displays in either zoom mode
4980  {
4981  Display->ZoomOutFlag = false;
4983  }
4984  ClearandRebuildRailway(72); // if was zoomed out this displays the track because until ZoomOutFlag reset PlotOutput plots nothing
4985  TPoint MainScreenPoint(ScreenPosH + 8, ScreenPosV + 8); // new v2.2.0 add 8 to centre pointer in element
4986  TPoint CursPos = MainScreen->ClientToScreen(MainScreenPoint); // accurate funtion to convert from local to global co-ordinates
4987  Mouse->CursorPos = CursPos;
4988  }
4989  else // mbRight, reset OAListBoxRightMouseButtonDown
4990  {
4992  }
4993  Utilities->CallLogPop(2090);
4994  }
4995  catch(const Exception &e)
4996  {
4997  ErrorLog(200, e.Message);
4998  }
4999 }
5000 
5001 // ---------------------------------------------------------------------------
5002 
5003 void __fastcall TInterface::OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5004 {
5005  try
5006  {
5007  TrainController->LogEvent("OAListBoxMouseDown," + AnsiString(X) + "," + AnsiString(Y));
5008  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseDown");
5009  if(Button == mbRight)
5010  {
5012  }
5013  Utilities->CallLogPop(2264);
5014  }
5015  catch(const Exception &e)
5016  {
5017  ErrorLog(220, e.Message);
5018  }
5019 }
5020 
5021 // ---------------------------------------------------------------------------
5022 
5023 bool TInterface::GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &TrackVectorPosition)
5024 // returns true if value(s) valid
5025 {
5026  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetTrainIDOrContinuationPosition");
5028  // find item required - 13 pixels per line of text
5029  int TopPos = OAListBox->TopIndex;
5030  int OAIndex;
5031  if((TopPos + (Y / 13)) >= OAListBox->Items->Count) // if click beyond end of list ignore
5032  {
5033  Utilities->CallLogPop(2089);
5034  return(false);
5035  }
5036  else
5037  {
5038  OACurrentEntryPtr = TrainController->OpTimeToActMultiMap.begin();
5039  std::advance(OACurrentEntryPtr, ((Y / 13) + TopPos));
5040  }
5041  int TrainIDorTVPos = OACurrentEntryPtr->second.second;
5042  if(TrainIDorTVPos >= 0) // running train, so value is the TrainID
5043  {
5044  if(TrainController->TrainExistsAtIdent(0, TrainIDorTVPos)) // added at v2.4.0 in case train removed but still in OA list as not updated yet
5045  // see LiWinDom error report on Discord 23/04/20. Also needed for click OAListBox before any trains show,
5046  // as notified by Rokas Serys by email on 16/05/20
5047  {
5048  TrainID = TrainIDorTVPos;
5049  TrackVectorPosition = TrainController->TrainVectorAtIdent(43, TrainIDorTVPos).LeadElement;
5050  }
5051  else
5052  {
5053  Utilities->CallLogPop(2155); // if not there then ignore
5054  return(false);
5055  }
5056  }
5057  else // train to enter at a continuation, so value is -TVPos of continuation - 1
5058  {
5059  TrackVectorPosition = -(TrainIDorTVPos + 1);
5060  }
5061  Utilities->CallLogPop(2261);
5062  return(true);
5063 }
5064 
5065 // ---------------------------------------------------------------------------
5066 
5068 {
5069  enum
5070  {
5071  PreStartTime, ActiveSegment, PostEnd
5072  } Segment;
5073  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CompileAllEntriesMemoAndSetPointers");
5074  AllEntriesTTListBox->Clear();
5075  TEVPtr = 0;
5076  TTStartTimePtr = 0;
5077  TTFirstServicePtr = 0;
5078  TTLastServicePtr = 0; // all set to null to begin with
5079  if(TimetableEditVector.empty())
5080  {
5081  TTCurrentEntryPtr = 0;
5082  Utilities->CallLogPop(1681);
5083  return;
5084  }
5085  Segment = PreStartTime;
5086  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
5087  {
5088  if(Segment == PreStartTime) // looking for the start time
5089  {
5090  TDateTime TempTime; // dummy
5091  if(TrainController->CheckTimeValidity(33, *TEVPtr, TempTime))
5092  {
5093  TTStartTimePtr = TEVPtr; // TTStartTimeBox text set in TTHandler
5094  AllEntriesTTListBox->Items->Add("START " + (*TEVPtr).SubString(1, 5));
5095  Segment = ActiveSegment;
5096  continue;
5097  }
5098  else
5099  {
5100  if(*TEVPtr == "")
5101  {
5102  AllEntriesTTListBox->Items->Add("- Blank");
5103  }
5104  else
5105  {
5106  AnsiString CurrentStr = *TEVPtr;
5107  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5108  {
5109  CurrentStr = CurrentStr.SubString(1, 10); // limit length for LH window
5110  for(int x = 1; x < CurrentStr.Length(); x++)
5111  {
5112  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5113  {
5114  CurrentStr = CurrentStr.SubString(1, (x - 1));
5115  }
5116  }
5117  }
5118  AllEntriesTTListBox->Items->Add("- " + CurrentStr);
5119  }
5120  continue;
5121  }
5122  }
5123  if(Segment == ActiveSegment)
5124  {
5125  if(*TEVPtr != "")
5126  {
5127  if((*TEVPtr)[1] != '*')
5128  {
5130  ConvertCRLFsToCommas(0, *TEVPtr); // This needed because an entry intended as a service might have skipped the conversion in
5131  // SaveTTEntryButtonClick - see comment in that function
5132  if(TTFirstServicePtr == 0)
5133  {
5135  }
5137  }
5138  AnsiString Entry = *TEVPtr;
5139 
5140 /* dropped at v2.9.1 so comment entries more meaningful, they self truncate to AllEntriesTTListBox width
5141  if(Entry[1] == '*')
5142  {
5143  Entry = "Comment";
5144  }
5145 */
5146  if(Entry[1] != '*') //changed from 'else' at v2.9.1
5147  {
5148  int SCPos = Entry.Pos(';'); // semicolon
5149  int CPos = Entry.Pos(','); // comma
5150  // 5 possibilities: no comma & no semicolon - just text - enter 1st 12 characters
5151  // both, comma before semicolon, i.e text on its own line, semicolon on next line - e.g. service headcode but no
5152  // description - enter the text up to the comma
5153  // both, semicolon before comma, normal - enter text up to the semicolon
5154  // comma & no semicolon, one or more lines of text without any semicolons - enter the text up to the comma
5155  // semicolon & no comma - enter text up to the semicolon
5156  if((CPos == 0) && (SCPos == 0))
5157  {
5158  Entry = Entry.SubString(1, 12);
5159  }
5160  else if((CPos > 0) && (SCPos > 0) && (CPos < SCPos))
5161  {
5162  Entry = Entry.SubString(1, CPos - 1);
5163  }
5164  else if((CPos > 0) && (SCPos > 0) && (CPos > SCPos))
5165  {
5166  Entry = Entry.SubString(1, SCPos - 1);
5167  }
5168  else if((CPos > 0) && (SCPos == 0))
5169  {
5170  Entry = Entry.SubString(1, CPos - 1);
5171  }
5172  else
5173  {
5174  Entry = Entry.SubString(1, SCPos - 1);
5175  }
5176  }
5177  AllEntriesTTListBox->Items->Add(Entry);
5178  continue;
5179  }
5180  else
5181  {
5182  Segment = PostEnd;
5183  AllEntriesTTListBox->Items->Add("END (Blank)");
5184  continue;
5185  }
5186  }
5187  if(Segment == PostEnd)
5188  {
5189  if(*TEVPtr == "")
5190  {
5191  AllEntriesTTListBox->Items->Add("+ Blank");
5192  }
5193  else
5194  {
5195  AnsiString CurrentStr = *TEVPtr;
5196  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5197  {
5198  CurrentStr = CurrentStr.SubString(1, 10);
5199  for(int x = 1; x < CurrentStr.Length(); x++)
5200  {
5201  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5202  {
5203  CurrentStr = CurrentStr.SubString(1, (x - 1));
5204  }
5205  }
5206  }
5207  AllEntriesTTListBox->Items->Add("+ " + CurrentStr);
5208  }
5209  continue;
5210  }
5211  }
5212  if(TTStartTimePtr == 0)
5213  {
5214  TTStartTimeBox->Text = "";
5215  }
5216  TTCurrentEntryPtr = TTLastServicePtr; // may well be reset outside this function but need to ensure that it has a valid value on exit, even if it's null
5217  Utilities->CallLogPop(1680);
5218 }
5219 // ---------------------------------------------------------------------------
5220 
5221 void __fastcall TInterface::AZOrderButtonClick(TObject *Sender)
5222 {
5223  try
5224  {
5225  if(TimetableEditVector.empty())
5226  {
5227  return; // should be able to access this if it is but keep in for safety
5228  }
5229  TrainController->LogEvent("AZOrderClick");
5230  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AZOrderClick");
5231  if(AZOrderButton->Caption == AnsiString("A-Z Order"))
5232  {
5233  TTEVPtr SortStart, SortEnd;
5234  UnicodeString MessageStr =
5235  "If you wish to preserve the original order don't save any changes whilst in alphabetical order.\n\n" "To preserve the original order use alphabetical order to find the service required, click it to display it,"
5236  " then revert to the original order where the same service will be displayed and can be changed.";
5237  Application->MessageBox(MessageStr.c_str(), L"Please Note:", MB_OK | MB_ICONWARNING);
5240  SortStart = TimetableEditVector.begin(); // if no start time set sort from beginning
5241  if(TTFirstServicePtr != NULL)
5242  {
5243  SortStart = TTFirstServicePtr;
5244  }
5245  SortEnd = TimetableEditVector.end(); // if no last service set sort to end
5246  if(TTLastServicePtr != NULL)
5247  {
5248  SortEnd = TTLastServicePtr + 1;
5249  }
5250  std::sort(SortStart, SortEnd);
5252  bool CurrentEntryChanged = false;
5253  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5254  {
5255  if(TTSelectedEntry == *x)
5256  {
5257  TTCurrentEntryPtr = x;
5258  CurrentEntryChanged = true;
5259  }
5260  }
5261  if(!CurrentEntryChanged)
5262  {
5264  }
5265  AZOrderButton->Caption = AnsiString("Original Order");
5266  AZOrderButton->Hint = AnsiString("Arrange services in original order Toggle with Shift+ Z");
5267  }
5268  else
5269  {
5271  {
5272  UnicodeString MessageStr =
5273  "Reverting to the original order will discard any changes made whilst in alphabetical order.\n\nTo preserve the changes click 'No', then save the timetable or use 'save as' if you wish to keep the original timetable.\n\nDo you wish to proceed?";
5274  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
5275  if(button == IDNO)
5276  {
5277  TimetableChangedFlag = true;
5278  TimetableValidFlag = false;
5280  SetLevel1Mode(135);
5281  Utilities->CallLogPop(2166);
5282  return;
5283  }
5284  }
5288  bool CurrentEntryChanged = false;
5289  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5290  {
5291  if(TTSelectedEntry == *x)
5292  {
5293  TTCurrentEntryPtr = x;
5294  CurrentEntryChanged = true;
5295  }
5296  }
5297  if(!CurrentEntryChanged)
5298  {
5300  }
5301  AZOrderButton->Caption = AnsiString("A-Z Order");
5302  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
5303  }
5304 // TimetableChangedFlag = true; dropped for v2.11.0
5305  TimetableValidFlag = false;
5308  SetLevel1Mode(136);
5309  Utilities->CallLogPop(2165);
5310  }
5311  catch(const Exception &e)
5312  {
5313  ErrorLog(211, e.Message);
5314  }
5315 }
5316 
5317 // ---------------------------------------------------------------------------
5318 
5319 void TInterface::ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
5320 {
5321  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertCRLFsToCommas," + ConvStr);
5322  AnsiString OutStr = "";
5323  int x = 1; // AnsiString arrays start at 1
5324 
5325  while(x < ConvStr.Length()) // skip the last character as looking for CRLF pairs, i.e. '\r' followed by '\n'
5326  {
5327  if((ConvStr[x] == '\r') && (ConvStr[x + 1] == '\n'))
5328  {
5329  OutStr += ',';
5330  x++;
5331  x++;
5332  }
5333  else
5334  {
5335  OutStr += ConvStr[x];
5336  x++;
5337  }
5338  }
5339  if(x == ConvStr.Length())
5340  {
5341  OutStr += ConvStr[x]; // add the last character
5342 
5343  }
5344 // strip any excess commas from the end
5345  if(OutStr != "")
5346  {
5347  while(OutStr[OutStr.Length()] == ',')
5348  {
5349  OutStr = OutStr.SubString(1, OutStr.Length() - 1);
5350  if(OutStr == "")
5351  {
5352  break; // if consisted of just commas then without this would fail on range error when becomes a null string
5353  }
5354  }
5355  }
5356  ConvStr = OutStr;
5357  if(ConvStr == "")
5358  {
5359  ConvStr = ','; // don't return a null or will fail, OK to return a comma on its own as will be ignored during ProcessOneTimetableLine
5360  }
5361  // when AllCommas will be true
5362  Utilities->CallLogPop(1846);
5363 }
5364 
5365 // ---------------------------------------------------------------------------
5366 
5368 {
5369 /* CreateEditTTFileName set if a TT file loaded (even if empty), the pointers TTStartTimePtr, TTFirstServicePtr, TTLastServicePtr provide
5370  relevant information - if null then not set. TTCurrentEntryPtr is set to the Entry to be displayed or null if there's no start time or no
5371  entries
5372 */
5373  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableHandler");
5374  PreviousTTEntryButton->Enabled = false;
5375  NextTTEntryButton->Enabled = false;
5376  AddMinsButton->Enabled = false;
5377  SubMinsButton->Enabled = false;
5378  CopyTTEntryButton->Enabled = false;
5379  CutTTEntryButton->Enabled = false;
5380  PasteTTEntryButton->Enabled = false;
5381  DeleteTTEntryButton->Enabled = false;
5382  SaveTTEntryButton->Enabled = false;
5383  SaveTTButton->Enabled = false;
5384  SaveTTAsButton->Enabled = false;
5385  ValidateTimetableButton->Enabled = false;
5386  AZOrderButton->Enabled = false;
5387  TTServiceSyntaxCheckButton->Enabled = false;
5388  NewTTEntryButton->Enabled = false;
5389  MoveTTEntryUpButton->Enabled = false;
5390  MoveTTEntryDownButton->Enabled = false;
5391  CancelTTEntryButton->Enabled = false;
5392  RestoreTTButton->Enabled = false;
5393  ExportTTButton->Enabled = false;
5394  ConflictAnalysisButton->Enabled = false;
5395  ExitTTModeButton->Enabled = true;
5396 
5398  {
5399  AZOrderButton->Enabled = true;
5400  }
5402  {
5403  TimetableValidFlag = false; // should always be the case anyway but include here to be sure
5404 
5405  }
5406  if(CreateEditTTFileName == "")
5407  {
5408  TimetableNameLabel->Caption = "Creating new timetable: not yet saved";
5409  }
5410  else
5411  {
5412  TimetableNameLabel->Caption = "Editing timetable: " + CreateEditTTTitle;
5413  }
5414  if(TTStartTimePtr != 0) // Null means start time not yet set
5415  {
5416  TTStartTimeBox->Text = (*TTStartTimePtr).SubString(1, 5); // 1st 5 chars = time if validity check OK
5417  }
5418 // start time now set & displayed
5419 
5421  {
5422  InfoPanel->Visible = true;
5423  InfoPanel->Caption = "Select option or change entry";
5424  if(RailwayTitle != "")
5425  {
5426  ShowHideTTButton->Enabled = true;
5427  }
5428  else
5429  {
5430  ShowHideTTButton->Enabled = false;
5431  }
5432  ExitTTModeButton->Enabled = true;
5433  AllEntriesTTListBox->Enabled = true;
5434  AnsiString AnsiAddSubText(AddSubMinsBox->Text);
5435  if((AnsiAddSubText != "") && AreAnyTimesInCurrentEntry())
5436  {
5437  bool ValidFlag = true;
5438  for(int x = 1; x <= AnsiAddSubText.Length(); x++)
5439  {
5440  if((AnsiAddSubText[x] > '9') || (AnsiAddSubText[x] < '0'))
5441  {
5442  ValidFlag = false;
5443  break;
5444  }
5445  }
5446  if(ValidFlag)
5447  {
5448  if(AnsiAddSubText.ToInt() != 0)
5449  {
5450  AddMinsButton->Enabled = true;
5451  SubMinsButton->Enabled = true;
5452  }
5453  }
5454  }
5456  {
5457  RestoreTTButton->Enabled = true;
5458  }
5460  {
5461  // Need !TimetableChangedFlag because the changed TT must be saved before validation - it's the TT file that is checked
5462  // so if it is changed but not saved, the 'correct' file will check OK but the changed TT may well not be valid
5463  ValidateTimetableButton->Enabled = true;
5464  }
5466  {
5467  ExportTTButton->Enabled = true;
5468  ConflictAnalysisButton->Enabled = true;
5469  }
5470  if(TTCurrentEntryPtr != 0)
5471  {
5472  CopyTTEntryButton->Enabled = true;
5473  CutTTEntryButton->Enabled = true;
5474  DeleteTTEntryButton->Enabled = true;
5475  }
5476  if((TimetableChangedFlag) && !TimetableEditVector.empty())
5477  {
5478  SaveTTButton->Enabled = true;
5479  }
5480  if(!TimetableEditVector.empty())
5481  {
5482  SaveTTAsButton->Enabled = true;
5483  }
5485  {
5486  NewTTEntryButton->Enabled = true;
5487  }
5488  if((TTCurrentEntryPtr > 0) && !TimetableEditVector.empty())
5489  {
5490  if((TimetableEditVector.end() - 1) > TTCurrentEntryPtr)
5491  {
5492  NextTTEntryButton->Enabled = true;
5493  MoveTTEntryDownButton->Enabled = true;
5494  }
5496  {
5497  PreviousTTEntryButton->Enabled = true;
5498  MoveTTEntryUpButton->Enabled = true;
5499  }
5500  }
5501  if(TTCurrentEntryPtr > 0)
5502  {
5503  if(*TTCurrentEntryPtr != "")
5504  {
5506  {
5507  TTServiceSyntaxCheckButton->Enabled = true;
5508  }
5509  }
5510  }
5511  if(CopiedEntryFlag)
5512  {
5513  PasteTTEntryButton->Enabled = true;
5514  }
5515  OneEntryTimetableMemo->Clear(); // don't clear if Entry changed
5516  if(TTCurrentEntryPtr > 0)
5517  {
5518 // if(*TTCurrentEntryPtr != "") leave this out or fails to highlight blank line entries
5520  {
5521  bool ServiceEntry = true;
5522  DisplayOneTTLineInPanel(0, *TTCurrentEntryPtr, ServiceEntry);
5523  }
5524  else
5525  {
5526  bool ServiceEntry = false;
5527  DisplayOneTTLineInPanel(1, *TTCurrentEntryPtr, ServiceEntry);
5528  }
5529  }
5530  }
5531  else
5532  {
5533  CancelTTEntryButton->Enabled = true;
5534  SaveTTEntryButton->Enabled = true;
5535  ShowHideTTButton->Enabled = false;
5536  ExitTTModeButton->Enabled = false;
5537  AllEntriesTTListBox->Enabled = false; // to stop entries being selected
5538  InfoPanel->Caption = "Add or change entry then save it, or cancel";
5539  InfoPanel->Visible = true;
5540  }
5541  Utilities->CallLogPop(1600);
5542 }
5543 
5544 // ---------------------------------------------------------------------------
5545 void TInterface::DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
5546 {
5547  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisplayOneTTLineInPanel," + Data + ", " +
5548  AnsiString((short)ServiceEntry));
5549  OneEntryTimetableMemo->Clear();
5550  if(ServiceEntry)
5551  {
5552  TrainController->StripSpaces(1, Data);
5553  while(true)
5554  {
5555  int CommaPos = Data.Pos(',');
5556  if((CommaPos == 0) && (Data != ""))
5557  {
5558  CommaPos = Data.Length() + 1;
5559  }
5560  OneEntryTimetableMemo->Lines->Add(Data.SubString(1, CommaPos - 1));
5561  if(Data.Length() <= CommaPos)
5562  {
5563  break;
5564  }
5565  Data = Data.SubString(CommaPos + 1, Data.Length() - CommaPos);
5566  }
5567  }
5568  else
5569  {
5570  OneEntryTimetableMemo->Text = Data;
5571  }
5572  int TotalLines = OneEntryTimetableMemo->Lines->Count; // remove excess lines at bottom
5573 
5574  while((OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "") || (OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "\r\n"))
5575  {
5576  OneEntryTimetableMemo->Lines->Delete(TotalLines - 1);
5577  TotalLines--;
5578  if(TotalLines < 1)
5579  {
5580  break;
5581  }
5582  }
5583  OneEntryTimetableMemo->HideSelection = true;
5584  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
5585  OneEntryTimetableMemo->SelLength = 0;
5587  Utilities->CallLogPop(1602);
5588 }
5589 // ---------------------------------------------------------------------------
5590 
5592 {
5593  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighlightOneEntryInAllEntriesTTListBox," + AnsiString(Position));
5594  if(TimetableEditVector.empty() || (AllEntriesTTListBox->Items->Count == 0))
5595  {
5596  HighlightPanel->Top = 32;
5597  HighlightPanel->Caption = "";
5598  HighlightPanel->Width = 100;
5599  HighlightPanel->Visible = false;
5600  }
5601  else
5602  {
5603  AnsiString CurrentStr = AllEntriesTTListBox->Items->Strings[Position];
5604  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5605  {
5606  for(int x = 1; x < CurrentStr.Length(); x++)
5607  {
5608  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5609  {
5610  CurrentStr = CurrentStr.SubString(1, (x - 1));
5611  }
5612  }
5613  }
5614  HighlightPanel->Top = 32 + (Position * 13) - (AllEntriesTTListBox->TopIndex * 13);
5615  if(HighlightPanel->Top < 32)
5616  {
5617  HighlightPanel->Visible = false;
5618  }
5619  else
5620  {
5621  HighlightPanel->Visible = true; // doesn't matter if goes off the bottom as it becomes invisible as then it's off its parent panel
5622  }
5623  HighlightPanel->Caption = CurrentStr;
5624  if(AllEntriesTTListBox->Items->Count > 47) // because the scrollbar will be present
5625  {
5626  HighlightPanel->Width = 82;
5627  }
5628  else
5629  {
5630  HighlightPanel->Width = 100;
5631  }
5632  }
5633  Utilities->CallLogPop(1709);
5634 }
5635 
5636 // ---------------------------------------------------------------------------
5638 {
5639  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == ""))
5640  {
5641  return(false);
5642  }
5643  TDateTime DummyTime;
5644  bool TimesPresent = false;
5645 
5646  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
5647  {
5648  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
5649  {
5650  if(TrainController->CheckTimeValidity(20, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
5651  {
5652  TimesPresent = true;
5653  break;
5654  }
5655  }
5656  if(TimesPresent)
5657  {
5658  break;
5659  }
5660  }
5661  return(TimesPresent);
5662 }
5663 
5664 // ---------------------------------------------------------------------------
5665 // end of Timetable editing functions
5666 // ---------------------------------------------------------------------------
5667 void __fastcall TInterface::ExitMenuItemClick(TObject *Sender)
5668 {
5669  try
5670  {
5671  TrainController->LogEvent("ExitMenuItemClick");
5672  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitMenuItemClick");
5673 /* Dropped at v2.9.1 as serves no apparent purpose
5674  if(!FileChangedFlag && !(Track->IsTrackFinished()) && (EveryPrefDir->PrefDirSize() > 0))
5675  {
5676  UnicodeString MessageStr =
5677  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
5678  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5679  if(button == IDNO)
5680  {
5681  Utilities->CallLogPop(1711);
5682  return;
5683  }
5684  }
5685 */
5686  if(FileChangedFlag)
5687  {
5688  UnicodeString MessageStr = "The railway has changed, exit without saving?";
5689  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5690  if(button == IDNO)
5691  {
5692  Utilities->CallLogPop(1180);
5693  return;
5694  }
5695  }
5696  if((TempTTFileName != "") && FileExists(TempTTFileName))
5697  {
5698  DeleteFile(TempTTFileName);
5699  }
5700  Utilities->CallLogPop(1181);
5701  Application->Terminate();
5702  }
5703  catch(const Exception &e)
5704  {
5705  ErrorLog(140, e.Message);
5706  }
5707 }
5708 // ---------------------------------------------------------------------------
5709 
5710 void __fastcall TInterface::TrackInfoOnOffMenuItemClick(TObject *Sender)
5711 {
5712  try
5713  {
5714  TrainController->LogEvent("TrackInfoOnOffMenuItemClick");
5715  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackInfoOnOffMenuItemClick");
5716  if(TrackInfoOnOffMenuItem->Caption == "Show")
5717  {
5718  TrackInfoOnOffMenuItem->Caption = "Hide";
5719  }
5720  else
5721  {
5722  TrackInfoOnOffMenuItem->Caption = "Show";
5723  }
5724  Utilities->CallLogPop(1183);
5725  }
5726  catch(const Exception &e)
5727  {
5728  ErrorLog(173, e.Message);
5729  }
5730 }
5731 // ---------------------------------------------------------------------------
5732 
5733 void __fastcall TInterface::TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
5734 {
5735  try
5736  {
5737  TrainController->LogEvent("TrainStatusInfoOnOffMenuItemClick");
5738  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainStatusInfoOnOffMenuItemClick");
5739  if(TrainStatusInfoOnOffMenuItem->Caption == "Show Status")
5740  {
5741  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status";
5742  }
5743  else
5744  {
5745  TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
5746  }
5747  Utilities->CallLogPop(1184);
5748  }
5749  catch(const Exception &e)
5750  {
5751  ErrorLog(141, e.Message);
5752  }
5753 }
5754 
5755 // ---------------------------------------------------------------------------
5756 void __fastcall TInterface::TrainTTInfoOnOffMenuItemClick(TObject *Sender)
5757 {
5758  try
5759  {
5760  TrainController->LogEvent("TrainTTInfoOnOffMenuItemClick");
5761  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainTTInfoOnOffMenuItemClick");
5762  if(TrainTTInfoOnOffMenuItem->Caption == "Show Timetable")
5763  {
5764  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable";
5765  }
5766  else
5767  {
5768  TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
5769  }
5770  Utilities->CallLogPop(1185);
5771  }
5772  catch(const Exception &e)
5773  {
5774  ErrorLog(142, e.Message);
5775  }
5776 }
5777 
5778 // ---------------------------------------------------------------------------
5779 // Dragging Functions
5780 // ---------------------------------------------------------------------------
5781 void __fastcall TInterface::AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
5782 {
5783 // allow in zoom out mode
5784  try
5785  {
5786 // TrainController->LogEvent("AcceptDragging"); drop this, have too many
5787  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AcceptDragging");
5788  if((Source == PerformancePanel) || (Source == PerformancePanelLabel) || (Source == PerformanceLogBox))
5789  {
5790  Accept = true;
5791  int PPLeft = PerformancePanel->Left;
5792  int PPTop = PerformancePanel->Left;
5793 
5794  PPLeft = Mouse->CursorPos.x - PerformancePanelDragStartX;
5795  PPTop = Mouse->CursorPos.y - PerformancePanelDragStartY;
5796  if((PPLeft + PerformancePanel->Width) < 32)
5797  {
5798  PPLeft = 32 - PerformancePanel->Width;
5799  }
5800  if(PPLeft > (MainScreen->Left + MainScreen->Width))
5801  {
5802  PPLeft = MainScreen->Left + MainScreen->Width;
5803  }
5804  if((PPTop + PerformancePanel->Height) < MainScreen->Top)
5805  {
5806  PPTop = MainScreen->Top - PerformancePanel->Height;
5807  }
5808  if(PPTop > (MainScreen->Top + MainScreen->Height - 20))
5809  {
5810  PPTop = MainScreen->Top + MainScreen->Height - 20;
5811  }
5812  PerformancePanel->Left = PPLeft;
5813  PerformancePanel->Top = PPTop;
5814  }
5815  else if((Source == OperatorActionPanel) || (Source == OAPanelLabel))
5816  // not the listbox because that used for selecting trains
5817  {
5818  Accept = true;
5819  int OALeft = OperatorActionPanel->Left;
5820  int OATop = OperatorActionPanel->Left;
5821 
5822  OALeft = Mouse->CursorPos.x - OperatorActionPanelDragStartX;
5823  OATop = Mouse->CursorPos.y - OperatorActionPanelDragStartY;
5824  if((OALeft + OperatorActionPanel->Width) < 32)
5825  {
5826  OALeft = 32 - OperatorActionPanel->Width;
5827  }
5828  if(OALeft > (MainScreen->Left + MainScreen->Width))
5829  {
5830  OALeft = MainScreen->Left + MainScreen->Width;
5831  }
5832  if((OATop + OperatorActionPanel->Height) < MainScreen->Top)
5833  {
5834  OATop = MainScreen->Top - OperatorActionPanel->Height;
5835  }
5836  if(OATop > (MainScreen->Top + MainScreen->Height - 20))
5837  {
5838  OATop = MainScreen->Top + MainScreen->Height - 20;
5839  }
5840  OperatorActionPanel->Left = OALeft;
5841  OperatorActionPanel->Top = OATop;
5842  }
5843  else
5844  {
5845  Accept = false;
5846  }
5847  Utilities->CallLogPop(1186);
5848  }
5849  catch(const Exception &e)
5850  {
5851  ErrorLog(143, e.Message);
5852  }
5853 }
5854 
5855 // ---------------------------------------------------------------------------
5856 void __fastcall TInterface::PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
5857 {
5858 // allow in zoom out mode
5859  try
5860  {
5861  TrainController->LogEvent("PerformancePanelStartDrag");
5862  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelStartDrag");
5863  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
5864  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
5865  Utilities->CallLogPop(1187);
5866  }
5867  catch(const Exception &e)
5868  {
5869  ErrorLog(144, e.Message);
5870  }
5871 }
5872 // ---------------------------------------------------------------------------
5873 
5874 void __fastcall TInterface::OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject) // new v2.2.0
5875 
5876 {
5877 // allow in zoom out mode
5878  try
5879  {
5880  TrainController->LogEvent("OperatorActionPanelStartDrag");
5881  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionPanelStartDrag");
5882  OperatorActionPanelDragStartX = Mouse->CursorPos.x - OperatorActionPanel->Left;
5883  OperatorActionPanelDragStartY = Mouse->CursorPos.y - OperatorActionPanel->Top;
5884  Utilities->CallLogPop(2091);
5885  }
5886  catch(const Exception &e)
5887  {
5888  ErrorLog(201, e.Message);
5889  }
5890 }
5891 
5892 // ---------------------------------------------------------------------------
5893 // Mouse Functions
5894 // ---------------------------------------------------------------------------
5895 void __fastcall TInterface::MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5896 // caller function - stops master clock
5897 {
5898 // have to allow in zoom out mode
5899  try
5900  {
5901  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseDown," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5902  bool ClockState = Utilities->Clock2Stopped;
5903  Utilities->Clock2Stopped = true;
5904 
5905  RestoreFocusPanel->Enabled = true; // these added at v2.0.0 to restore navigation keys to move screen when a panel had focus
5906  RestoreFocusPanel->Visible = true; // because then these buttons just cycled through the panel buttons. Added in place of the
5907  RestoreFocusPanel->SetFocus(); // section in ClockTimer2 where focus restored every clock cycle, because then the help screen
5908  RestoreFocusPanel->Visible = false; // was hidden. At least now help is only hidden when the screen clicked, which is normal
5909  RestoreFocusPanel->Enabled = false; // behaviour, and can tell user that can restore navigation keys just by clicking the screen
5910  MMoveTrackSelFlag = false;
5911  MMovePrefDirSelFlag = false;
5915 
5917  {
5918  if(!Display->ZoomOutFlag)
5919  {
5920  MainScreenMouseDown2(0, Button, Shift, X, Y);
5921  }
5922  else
5923  {
5924  MainScreenMouseDown3(0, Button, Shift, X, Y);
5925  }
5926  }
5927  Utilities->Clock2Stopped = ClockState;
5928  Utilities->CallLogPop(33);
5929  }
5930  catch(const Exception &e)
5931  {
5932  ErrorLog(19, e.Message);
5933  }
5934 }
5935 
5936 // ---------------------------------------------------------------------------
5937 void TInterface::MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
5938 {
5939  try
5940  {
5941  TrainController->LogEvent("MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5942  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) +
5943  "," + AnsiString(Y));
5944  // unplot GapFlash graphics if plotted & cancel gap flashing if left mouse button pressed (so can move display with right mouse button)
5945  // but not in ZoomOut mode - so can switch between modes & keep gaps flashing
5946  HideTTActionsListBox(0); //get rid of this for any click on screen
5947  if(Track->GapFlashFlag && !Display->ZoomOutFlag && (Button == mbLeft))
5948  {
5951  Track->GapFlashFlag = false;
5952  }
5953  int HLoc, VLoc;
5954  Track->GetTrackLocsFromScreenPos(1, HLoc, VLoc, X, Y);
5955  int NoOffsetX, NoOffsetY;
5956  Track->GetTruePositionsFromScreenPos(0, NoOffsetX, NoOffsetY, X, Y);
5957  if(Button == mbRight) // track, PrefDir or text erase, PrefDir/route truncate, or take signaller control of train
5958  {
5959  // this routine new at v2.1.0. Allows railway moving for zoom-in mode when no element at HLoc & VLoc
5960  int Dummy; // unused in next function
5961  AnsiString Text = ""; // needed for TextFound but not used
5964  if(!Track->TrackElementPresentAtHV(0, HLoc, VLoc) && !Track->InactiveTrackElementPresentAtHV(0, HLoc, VLoc) && !Track->UserGraphicPresentAtHV(0, X,
5965  Y, Dummy) && !TextHandler->TextFound(0, X + (Display->DisplayOffsetH * 16), Y + (Display->DisplayOffsetV * 16), Text))
5966  {
5969  WholeRailwayMoving = true;
5970  Screen->Cursor = TCursor(-22); // Four arrows;
5971  }
5972 
5973  else if(Level2TrackMode == AddText)
5974  {
5975  TrainController->LogEvent("mbRight + AddText");
5976 // ResetChangedFileDataAndCaption(, true); moved from here after 2.7.0 in case no changes made
5977  if(TextHandler->TextFound(1, NoOffsetX, NoOffsetY, Text))
5978  {
5979  if(TextHandler->TextErase(0, NoOffsetX, NoOffsetY, Text)) // erase text in vector
5980  {
5981  ResetChangedFileDataAndCaption(2, true); // moved to here after 2.7.0
5983  if(NoRailway())
5984  {
5985  EditMenu->Enabled = false;
5986  }
5987  else
5988  {
5989  EditMenu->Enabled = true;
5990  }
5991  }
5992  }
5993  SetLevel2TrackMode(57); // to remove 'move text' if last text item removed
5994  Utilities->CallLogPop(34);
5995  return;
5996  }
5997  else if(Level2TrackMode == AddGraphic)
5998  {
5999  TrainController->LogEvent("mbRight + AddGraphic");
6000  if(Track->UserGraphicVector.empty()) // no user graphics
6001  {
6002  Utilities->CallLogPop(2180);
6003  return;
6004  }
6005  int UGIVecPos;
6006  if(Track->UserGraphicPresentAtHV(1, X, Y, UGIVecPos))
6007  {
6008  Track->UserGraphicVector.erase(Track->UserGraphicVector.begin() + UGIVecPos);
6010  if(NoRailway())
6011  {
6012  EditMenu->Enabled = false;
6013  }
6014  else
6015  {
6016  EditMenu->Enabled = true;
6017  }
6018  }
6019  Utilities->CallLogPop(2181);
6020  return;
6021  }
6022 
6023  else if(Level2TrackMode == AddTrack)
6024  {
6025  TrainController->LogEvent("mbRight + AddTrack");
6026  bool TrackEraseSuccessfulFlag;
6027  int ErasedTrackVectorPosition;
6028  Screen->Cursor = TCursor(-11); // Hourglass;
6029  Track->EraseTrackElement(1, HLoc, VLoc, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, true);
6030  if(TrackEraseSuccessfulFlag)
6031  {
6032  if(ErasedTrackVectorPosition > -1) //may have been an inactive element
6033  {
6034  EveryPrefDir->RealignAfterTrackErase(0, ErasedTrackVectorPosition);
6035  }
6038  ClearandRebuildRailway(5); // to ensure location named elements plotted correctly & replot the grid if required
6039  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6040  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6041  if(Track->GapsUnset(1))
6042  {
6043  SetGapsButton->Enabled = true;
6044  }
6045  // only enable if there are gaps still to be set (returns false for no track)
6046  else
6047  {
6048  if(!(Track->NoActiveTrack(0)) && !(Track->IsTrackFinished()))
6049  {
6050  TrackOKButton->Enabled = true;
6051  }
6052  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6053  }
6054  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6055  {
6056  SetLengthsButton->Enabled = false;
6057  }
6058 // if(NoRailway()) dropped at v2.6.0 to allow edits during AddTrack
6059 // {
6060 // EditMenu->Enabled = false;
6061 // }
6062 // else
6063  EditMenu->Enabled = true;
6064  }
6065  Screen->Cursor = TCursor(-2); // Arrow
6066  Utilities->CallLogPop(35);
6067  return;
6068  }
6069  else if(Level2TrackMode == DistanceContinuing) // new for extended distances (similar to PrefDirContinuing)
6070  {
6071  TrainController->LogEvent("mbRight + DistanceContinuing");
6072 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 as may only be checking existing distances/speeds. Moved to button clicks in TrackLengthPanel
6073  bool LeadingPointsAtLastElement = false;
6074  if(ConstructPrefDir->GetPrefDirTruncateElement(0, HLoc, VLoc))
6075  {
6076  if(ConstructPrefDir->PrefDirSize() == 0)
6077  {
6079  SetLevel1Mode(64);
6081  SetLevel2TrackMode(51); // calls ClearandRebuildRailway to show length erased & sets back to start
6082  Utilities->CallLogPop(1526);
6083  return;
6084  }
6087  ConstructPrefDir->CalcDistanceAndSpeed(0, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6088  if(!LeadingPointsAtLastElement)
6089  {
6090  TrackLengthPanel->Visible = true;
6091  TrackLengthPanel->SetFocus();
6092  InfoPanel->Visible = true;
6093  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6094  RestoreAllDefaultLengthsButton->Enabled = true;
6095  ResetDefaultLengthButton->Enabled = true;
6096  LengthOKButton->Enabled = true;
6097  DistanceBox->Text = AnsiString(OverallDistance);
6098  if(OverallSpeedLimit > -1)
6099  {
6100  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6101  }
6102  else
6103  {
6104  SpeedLimitBox->Text = "Mixed";
6105  }
6106  }
6107  else
6108  {
6109  TrackLengthPanel->Visible = true;
6110  TrackLengthPanel->SetFocus();
6111  InfoPanel->Visible = true;
6112  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, continue or truncate";
6113  RestoreAllDefaultLengthsButton->Enabled = false;
6114  ResetDefaultLengthButton->Enabled = false;
6115  LengthOKButton->Enabled = false;
6116  }
6118  }
6119  Utilities->CallLogPop(36);
6120  return;
6121  }
6122 
6123  else if(Level2PrefDirMode == PrefDirContinuing) // truncate
6124  {
6125  TrainController->LogEvent("mbRight + PrefDirContinuing");
6126 // ResetChangedFileDataAndCaption(, false); moved to later after 2.7.0 as may not change anything
6127 // RlyFile = false; - don't alter this just for PrefDir changes
6128  if(ConstructPrefDir->GetPrefDirTruncateElement(1, HLoc, VLoc))
6129  {
6130  if(ConstructPrefDir->PrefDirSize() == 0)
6131  {
6133  SetLevel1Mode(14); // all PrefDir truncated
6134  Utilities->CallLogPop(37);
6135  return;
6136  }
6138  ResetChangedFileDataAndCaption(5, false); // moved to here after 2.7.0
6139  }
6141  SetLevel2PrefDirMode(0); // calls ClearandRebuildRailway to show length erased & sets back to start
6142  Utilities->CallLogPop(38);
6143  return;
6144  }
6145 
6146  else if((Level1Mode == PrefDirMode) && (Level2PrefDirMode != PrefDirContinuing) && (Level2PrefDirMode != PrefDirSelecting)) // delete element
6147  {
6148  TrainController->LogEvent("mbRight + != PrefDirContinuing");
6150 // RlyFile = false; - don't alter this just for PrefDir changes
6153  SetLevel1Mode(15); // calls ClearandRebuildRailway to show length erased & sets back to start
6154  Utilities->CallLogPop(39);
6155  return;
6156  }
6157 
6158  else if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // disallow when paused, but allow some parts in prestart
6159  {
6160  TrainController->LogEvent("mbRight + OperMode");
6161  bool FoundFlag;
6162  int VecPos = Track->GetVectorPositionFromTrackMap(1, HLoc, VLoc, FoundFlag);
6163  if(FoundFlag && (Level2OperMode != PreStart)) // disallow train popup menu in PreStart
6164  {
6166  // display popup menu for the train
6167  if(SelectedTrainID > -1)
6168  {
6171  if(Train.TrainMode == Signaller)
6172  {
6173  if((Train.LeadElement == -1) || (Track->TrackElementAt(788, Train.LeadElement).Conn[Train.LeadExitPos] == -1)) //train front off continuation or on it
6174  {
6176  }
6177  else if(!Train.Stopped() && (Track->TrackElementAt(1450, (Track->TrackElementAt(1451, Train.LeadElement).Conn[Train.LeadExitPos])).TrackType == Continuation))
6178  { //added at v2.13.0 to prevent popup menu when train moving and front next to continuation
6180  }
6181  }
6182  if((Train.Stopped()) || (Train.TrainFailed && !(Train.TrainMode == Signaller)) ||
6184  !Train.StepForwardFlag))
6185  // don't allow signaller popup menu unless stopped, when failed in timetable mode, or in signaller mode provided that
6186  // train isn't stopping, leaving at a continuation or stepping forward
6187  {
6188  // don't allow selection if another stopped train at a bridge position
6189  if(Track->TrackElementAt(630, VecPos).TrackType == Bridge)
6190  {
6191  int TrainID01 = Track->TrackElementAt(631, VecPos).TrainIDOnBridgeTrackPos01;
6192  int TrainID23 = Track->TrackElementAt(632, VecPos).TrainIDOnBridgeTrackPos23;
6193  if((TrainID01 > -1) && (TrainID23 > -1))
6194  {
6195  TrainController->StopTTClockMessage(0, "Can't select a train at a bridge when another train is at the same bridge");
6196  Utilities->CallLogPop(1103);
6197  return;
6198  }
6199  }
6200  if(Train.TrainMode == Timetable)
6201  {
6202  TakeSignallerControlMenuItem->Enabled = true;
6203  TakeSignallerControlMenuItem->Visible = true;
6204  TimetableControlMenuItem->Enabled = false;
6205  TimetableControlMenuItem->Visible = false;
6206  ChangeDirectionMenuItem->Enabled = false;
6207  ChangeDirectionMenuItem->Visible = false;
6208  SkipTimetabledActionsMenuItem->Enabled = false;
6209  SkipTimetabledActionsMenuItem->Visible = false;
6210  MoveForwardsMenuItem->Enabled = false;
6211  MoveForwardsMenuItem->Visible = false;
6212  SignallerJoinedByMenuItem->Enabled = false;
6213  SignallerJoinedByMenuItem->Visible = false;
6214  RepairFailedTrainMenuItem->Enabled = false;
6215  RepairFailedTrainMenuItem->Visible = false;
6216  StepForwardMenuItem->Enabled = false;
6217  StepForwardMenuItem->Visible = false;
6218  RemoveTrainMenuItem->Enabled = false;
6219  RemoveTrainMenuItem->Visible = false;
6220  PassRedSignalMenuItem->Enabled = false;
6221  PassRedSignalMenuItem->Visible = false;
6222  SignallerControlStopMenuItem->Enabled = false;
6223  SignallerControlStopMenuItem->Visible = false;
6224  if((Train.StoppedAtSignal || Train.StoppedAtLocation) && !Train.ActionsSkippedFlag) //Exclude TreatPassAsTimeLocDeparture, otherwise skipping
6225  { //events causes problems that are best avoided
6226  SkipTimetabledActionsMenuItem->Enabled = true;
6227  SkipTimetabledActionsMenuItem->Visible = true;
6228  }
6229  BecomeNewServiceMenuItem->Enabled = false;
6230  BecomeNewServiceMenuItem->Visible = false;
6232  {
6233  BecomeNewServiceMenuItem->Enabled = true;
6234  BecomeNewServiceMenuItem->Visible = true;
6235  }
6236  }
6237  else // signaller mode
6238  {
6239  TakeSignallerControlMenuItem->Enabled = false;
6240  TakeSignallerControlMenuItem->Visible = false;
6241  SkipTimetabledActionsMenuItem->Enabled = false;
6242  SkipTimetabledActionsMenuItem->Visible = false;
6243  BecomeNewServiceMenuItem->Enabled = false;
6244  BecomeNewServiceMenuItem->Visible = false;
6245  if((Train.Crashed) || (Train.Derailed))
6246  {
6247  TimetableControlMenuItem->Enabled = false;
6248  TimetableControlMenuItem->Visible = false;
6249  ChangeDirectionMenuItem->Enabled = false;
6250  ChangeDirectionMenuItem->Visible = false;
6251  MoveForwardsMenuItem->Enabled = false;
6252  MoveForwardsMenuItem->Visible = false;
6253  SignallerJoinedByMenuItem->Enabled = false;
6254  SignallerJoinedByMenuItem->Visible = false;
6255  RepairFailedTrainMenuItem->Enabled = false;
6256  RepairFailedTrainMenuItem->Visible = false;
6257  StepForwardMenuItem->Enabled = false;
6258  StepForwardMenuItem->Visible = false;
6259  PassRedSignalMenuItem->Enabled = false;
6260  PassRedSignalMenuItem->Visible = false;
6261  SignallerControlStopMenuItem->Enabled = false;
6262  SignallerControlStopMenuItem->Visible = false;
6263  RemoveTrainMenuItem->Enabled = true;
6264  RemoveTrainMenuItem->Visible = true;
6265  }
6266  else if(Train.Stopped())
6267  {
6268  if(Train.TimetableFinished)
6269  {
6270  TimetableControlMenuItem->Enabled = false;
6271  TimetableControlMenuItem->Visible = false;
6272  }
6273  else
6274  {
6275  if(Train.RestoreTimetableLocation == "") // en route
6276  {
6277  TimetableControlMenuItem->Enabled = true;
6278  TimetableControlMenuItem->Visible = true;
6279  }
6280  else
6281  {
6282  // obtain train location & check if OK for restoration of tt control
6283  AnsiString LocName = "";
6284  if(Train.LeadElement > -1)
6285  {
6286  LocName = Track->TrackElementAt(802, Train.LeadElement).ActiveTrackElementName;
6287  }
6288  if((LocName == "") && (Train.MidElement > -1))
6289  {
6290  LocName = Track->TrackElementAt(803, Train.MidElement).ActiveTrackElementName;
6291  }
6292  if(Train.RestoreTimetableLocation == LocName)
6293  {
6294  TimetableControlMenuItem->Enabled = true;
6295  TimetableControlMenuItem->Visible = true;
6296  }
6297  else
6298  {
6299  TimetableControlMenuItem->Enabled = false;
6300  TimetableControlMenuItem->Visible = false;
6301  }
6302  }
6303  }
6304 // don't allow ChangeDirection if lead or mid elements (but not lag or next) -1, or lead, mid, lag or next elements continuations
6305  ChangeDirectionMenuItem->Enabled = true;
6306  ChangeDirectionMenuItem->Visible = true;
6307  if(Train.LeadElement > -1)
6308  {
6310  {
6311  ChangeDirectionMenuItem->Enabled = false;
6312  ChangeDirectionMenuItem->Visible = false;
6313  }
6314 /* drop this at v2.12.0, allow cdt for train stopped & leadelement next to exit continuation
6315  if(Track->TrackElementAt(, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
6316  {
6317  if(Track->TrackElementAt(, (Track->TrackElementAt(, Train.LeadElement).Conn[Train.LeadExitPos])).TrackType == Continuation)
6318  {
6319  ChangeDirectionMenuItem->Enabled = false;
6320  ChangeDirectionMenuItem->Visible = false;
6321  }
6322  }
6323 */
6324  }
6325  else
6326  {
6327  ChangeDirectionMenuItem->Enabled = false;
6328  ChangeDirectionMenuItem->Visible = false;
6329  }
6330  if(Train.MidElement > -1) //entering or exiting at a continuation
6331  {
6333  {
6334  ChangeDirectionMenuItem->Enabled = false;
6335  ChangeDirectionMenuItem->Visible = false;
6336  }
6337  }
6338  else
6339  {
6340  ChangeDirectionMenuItem->Enabled = false;
6341  ChangeDirectionMenuItem->Visible = false;
6342  }
6343  if(Train.LagElement > -1)
6344  {
6346  {
6347  ChangeDirectionMenuItem->Enabled = false;
6348  ChangeDirectionMenuItem->Visible = false;
6349  }
6350  }
6351  RemoveTrainMenuItem->Enabled = true;
6352  RemoveTrainMenuItem->Visible = true;
6353  SignallerControlStopMenuItem->Enabled = false;
6354  SignallerControlStopMenuItem->Visible = false;
6355  SignallerJoinedByMenuItem->Enabled = false;
6356  SignallerJoinedByMenuItem->Visible = false;
6357  RepairFailedTrainMenuItem->Enabled = false;
6358  RepairFailedTrainMenuItem->Visible = false;
6359  StepForwardMenuItem->Enabled = false;
6360  StepForwardMenuItem->Visible = false;
6361  MoveForwardsMenuItem->Enabled = false;
6362  MoveForwardsMenuItem->Visible = false;
6363  PassRedSignalMenuItem->Enabled = false;
6364  PassRedSignalMenuItem->Visible = false;
6365  if(Train.AbleToMove(0) && !Train.TreatPassAsTimeLocDeparture) //TreatPassAsTimeLocDeparture added at v2.12.0 to prevent signaller movements
6366  { //for 'pseudo' TimeLoc departures
6367  MoveForwardsMenuItem->Enabled = true;
6368  MoveForwardsMenuItem->Visible = true;
6369  if((!Train.LeavingUnderSigControlAtContinuation) && (Track->TrackElementAt(791, Train.LeadElement).Conn[Train.LeadExitPos] > -1))
6370  { //added check for adjacent element not being a continuation at v2.12.0 as dont allow step forward as wouldn't stop
6372  {
6373  StepForwardMenuItem->Enabled = true; // added 'if' condition for v1.3.2 due to Carwyn Thomas error,
6374  StepForwardMenuItem->Visible = true;
6375  }
6376  }
6377  } // fails on trying to calc AutoSig time delay for resetting signals
6378 
6379  if(Train.AbleToMoveButForSignal(0) && !Train.TreatPassAsTimeLocDeparture) // may not be in AutoSigs route but disallow anyway as not needed at continuation
6380  { //TreatPassAsTimeLocDeparture addesd at v2.12.0 as above
6381  PassRedSignalMenuItem->Enabled = true;
6382  PassRedSignalMenuItem->Visible = true;
6383  StepForwardMenuItem->Enabled = true;
6384  StepForwardMenuItem->Visible = true;
6385  }
6386  TTrain *AdjacentTrain;
6387  if(Train.IsThereAnAdjacentTrain(0, AdjacentTrain))
6388  {
6389  SignallerJoinedByMenuItem->Enabled = true;
6390  SignallerJoinedByMenuItem->Visible = true;
6391  }
6392  if(Train.TrainFailed)
6393  {
6394  RepairFailedTrainMenuItem->Enabled = true;
6395  RepairFailedTrainMenuItem->Visible = true;
6396  }
6397  }
6398  else // train moving under signaller control - only permit restoration of TT control when stopped as could be in
6399  // mid move, & SetTrainMovementValues only intended to be called when stopped
6400  {
6401  TimetableControlMenuItem->Enabled = false;
6402  TimetableControlMenuItem->Visible = false;
6403  ChangeDirectionMenuItem->Enabled = false;
6404  ChangeDirectionMenuItem->Visible = false;
6405  RemoveTrainMenuItem->Enabled = false;
6406  RemoveTrainMenuItem->Visible = false;
6407  MoveForwardsMenuItem->Enabled = false;
6408  MoveForwardsMenuItem->Visible = false;
6409  SignallerJoinedByMenuItem->Enabled = false;
6410  SignallerJoinedByMenuItem->Visible = false;
6411  RepairFailedTrainMenuItem->Enabled = false;
6412  RepairFailedTrainMenuItem->Visible = false;
6413  PassRedSignalMenuItem->Enabled = false;
6414  PassRedSignalMenuItem->Visible = false;
6415  StepForwardMenuItem->Enabled = false;
6416  StepForwardMenuItem->Visible = false;
6417  SignallerControlStopMenuItem->Enabled = true;
6418  SignallerControlStopMenuItem->Visible = true;
6419  }
6420  }
6421  TrainHeadCodeMenuItem->Caption = Train.HeadCode + ":";
6422  BecomeNewServiceMenuItem->Caption = "Terminate here and become follow-on service " + Train.FollowOnServiceRef; //added at v2.12.0
6423  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6425  PopupMenu->Popup(MainScreen->Left + X, MainScreen->Top + Y + 43); // menu stops everything so reset timetable time when restarts,
6426  // new at v2.6.1, displays so that can't inadvertently click on a selection if click twice
6427  // 43 is the distance from the top of the screen to the top of TInterface
6428  TrainController->BaseTime = TDateTime::CurrentDateTime();
6430  Utilities->CallLogPop(40);
6431  return;
6432  }
6433  }
6434  }
6435  if(RouteMode == RouteContinuing) // clear a single element (clears whether use left or right mouse button) +allow in PreStart
6436  {
6437  TrainController->LogEvent("mbRight + RouteContinuing");
6439  Utilities->CallLogPop(41);
6440  return;
6441  }
6442 
6443  else if(RouteCancelFlag) // allow in PreStart
6444  {
6445  TrainController->LogEvent("mbRight + RouteCancelFlag");
6446  Screen->Cursor = TCursor(-11); // Hourglass;
6447  // stop clock as sometimes takes several seconds
6448  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6450  if(AllRoutes->GetAllRoutesTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute)) // updates LockedRouteClass
6451  {
6452  ClearandRebuildRailway(6); // to replot new shorter route
6453  }
6455  TrainController->BaseTime = TDateTime::CurrentDateTime();
6457  Screen->Cursor = TCursor(-2); // Arrow
6458  }
6459 
6460  else // gap flashing, don't allow to interfere with RouteCancelFlag
6461  {
6462  TrainController->LogEvent("mbRight, GapFlashingInOperOrPreStartMode");
6463  int Position;
6464  TTrackElement TrackElement;
6465  if(Track->FindNonPlatformMatch(4, HLoc, VLoc, Position, TrackElement))
6466  {
6467  ;
6468  }
6469  {
6470  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6471  {
6472  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(818, TrackElement.Conn[0]).TrainIDOnElement == -1))
6473  {
6474  // don't flash if train on either gap element
6475  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6480  Track->GapFlashRedPosition = Position;
6485  Track->GapFlashFlag = true;
6486  }
6487  }
6488  }
6489  Utilities->CallLogPop(42);
6490  return; // covers above else & included here in case any more usermodes added later
6491  }
6492  }
6493  // deal with gap selection - if no other right button selection - apply for any mode (also included in OperMode above)
6494  TrainController->LogEvent("mbRight, GapFlashingNotOperOrPreStartMode");
6495  int Position;
6496  TTrackElement TrackElement;
6497  if(Track->FindNonPlatformMatch(18, HLoc, VLoc, Position, TrackElement))
6498  {
6499  ;
6500  }
6501  {
6502  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6503  {
6504  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(819, TrackElement.Conn[0]).TrainIDOnElement == -1))
6505  {
6506  // don't flash if train on either gap element
6507  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6511  Track->GapFlashRedPosition = Position;
6515  Track->GapFlashFlag = true;
6516  }
6517  }
6518  }
6519  Utilities->CallLogPop(67);
6520  return; // covers above else & included here in case any more usermodes added later
6521  }
6522 
6523 // Left Mouse Button Functions
6524  if(RouteCancelFlag)
6525  {
6527  }
6528  mbLeftDown = true;
6529 
6530  if(Level2TrackMode == AddTrack)
6531  {
6532  TrainController->LogEvent("mbLeft + AddTrack");
6533  Screen->Cursor = TCursor(-11); // Hourglass;
6535  bool TrackLinkingRequiredFlag;
6536  int CurrentTag;
6537  TSpeedButton *TempSpeedButton = 0;
6538  if(CurrentSpeedButton)
6539  {
6540  CurrentTag = CurrentSpeedButton->Tag;
6541  TempSpeedButton = CurrentSpeedButton;
6542  }
6543  else
6544  {
6545  CurrentTag = 0;
6546  }
6547  bool InternalChecks = true;
6548  Track->PlotAndAddTrackElement(1, CurrentTag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, InternalChecks);
6549  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
6550  EditMenu->Enabled = true;
6551  if(Track->NamedLocationElementAt(1, HLoc, VLoc))
6552  {
6553  ClearandRebuildRailway(7); // so named location graphics plotted correctly
6554  }
6555  if(TrackLinkingRequiredFlag)
6556  {
6557  Track->SetTrackFinished(false);
6558  }
6559  SetTrackBuildImages(10);
6560  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6561  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6562  if(Track->GapsUnset(2))
6563  {
6564  SetGapsButton->Enabled = true;
6565  }
6566  // only enable if there are gaps still to be set (returns false for no track)
6567  else
6568  {
6569  if(!(Track->NoActiveTrack(1)) && !(Track->IsTrackFinished()))
6570  {
6571  TrackOKButton->Enabled = true;
6572  }
6573  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6574  }
6575  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6576  {
6577  SetLengthsButton->Enabled = false;
6578  }
6579  if(TempSpeedButton) // restore button if was pressed
6580  {
6581  CurrentSpeedButton = TempSpeedButton;
6582  CurrentSpeedButton->Down = true;
6583  }
6584  Screen->Cursor = TCursor(-2); // Arrow
6585  Utilities->CallLogPop(44);
6586  return;
6587  }
6588 
6589  else if(Level2TrackMode == AddGraphic)
6590  {
6591  TrainController->LogEvent("mbLeft + AddGraphic");
6592 // ResetChangedFileDataAndCaption(, false); //moved to later after 2.7.0 in case can't find it
6593  TUserGraphicItem NewGI;
6594  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
6595  if(UGMIt != Track->UserGraphicMap.end()) // if it is the end then nothing was found
6596  {
6597  NewGI.UserGraphic = UGMIt->second;
6598  NewGI.Width = UGMIt->second->Width;
6599  NewGI.Height = UGMIt->second->Height;
6601  NewGI.HPos = X + (Display->DisplayOffsetH * 16);
6602  NewGI.VPos = Y + (Display->DisplayOffsetV * 16);
6603  Track->UserGraphicVector.push_back(NewGI);
6604  Display->PlotAndAddUserGraphic(1, NewGI);
6605  ResetChangedFileDataAndCaption(24, false); // moved to here after 2.7.0
6606  }
6607  else
6608  {
6609  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
6610  Utilities->CallLogPop(2195);
6611  return;
6612  }
6613  MoveTextOrGraphicButton->Enabled = true;
6614  EditMenu->Enabled = true;
6615  Utilities->CallLogPop(2182);
6616  return;
6617  }
6618 
6619  else if(Level2TrackMode == AddLocationName)
6620  {
6621  TrainController->LogEvent("mbLeft + AddLocationName");
6622 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to LocationNameKeyUp in case nothing changed
6623  bool FoundFlag;
6624  TTrackElement TrackElement;
6625  AnsiString NameString;
6626  TTrack::TIMPair InactivePair = Track->GetVectorPositionsFromInactiveTrackMap(1, HLoc, VLoc, FoundFlag);
6627  if(!FoundFlag)
6628  {
6629  Utilities->CallLogPop(45);
6630  return; // inactive element not found (has to be a platform or named non-station location, can't select any other element)
6631  }
6632  TTrackElement& InactiveTrackElement1 = Track->InactiveTrackElementAt(28, InactivePair.first);
6633  TTrackElement& InactiveTrackElement2 = Track->InactiveTrackElementAt(29, InactivePair.second); // may be same element if only 1
6634  TTrackElement& ValidElement = InactiveTrackElement1;
6635  unsigned int ValidPosition;
6636  if((InactiveTrackElement1.TrackType != Platform) && (InactiveTrackElement2.TrackType != Platform) &&
6637  (InactiveTrackElement1.TrackType != NamedNonStationLocation) && (InactiveTrackElement2.TrackType != NamedNonStationLocation) &&
6638  (InactiveTrackElement1.TrackType != Concourse) && (InactiveTrackElement2.TrackType != Concourse))
6639  {
6640  Utilities->CallLogPop(46);
6641  return; // element not valid
6642  }
6643  if((InactiveTrackElement1.TrackType == Platform) || (InactiveTrackElement1.TrackType == NamedNonStationLocation) ||
6644  (InactiveTrackElement1.TrackType == Concourse))
6645  {
6646  ValidElement = InactiveTrackElement1;
6647  ValidPosition = InactivePair.first;
6648  }
6649  else if((InactiveTrackElement2.TrackType == Platform) || (InactiveTrackElement2.TrackType == NamedNonStationLocation) ||
6650  (InactiveTrackElement2.TrackType == Concourse))
6651  {
6652  ValidElement = InactiveTrackElement2;
6653  ValidPosition = InactivePair.second;
6654  }
6655  // now have required element as ValidElement & position in InactiveTrackvector as ValidPosition
6656 
6657  // put a square box round element to show selection
6658  Display->Rectangle(0, HLoc * 16, VLoc * 16, clB0G0R5, 0, 2);
6659  LocationNameTextBox->Visible = true;
6660  LocationNameTextBox->SetFocus();
6661  NameString = Track->GetLocationName(ValidPosition);
6662  LocationNameTextBox->Text = NameString;
6663  InfoPanel->Visible = true;
6664  InfoPanel->Caption = "NAMING LOCATIONS: Enter name, 'Carriage Return' to accept, 'Escape' to quit";
6665 
6666  Track->LNPendingList.clear();
6667  Track->LNPendingList.insert(Track->LNPendingList.end(), ValidPosition);
6668  Level2TrackMode = NoTrackMode; // if leave as AddLocationName can select other squares before enter name
6669  Utilities->CallLogPop(47);
6670  return;
6671  }
6672 
6673  else if(Level2TrackMode == DistanceStart) // new for extended distances - similar to !PrefDirContinuing
6674  // prior to selecting start element
6675  {
6676  TrainController->LogEvent("mbLeft + DistanceStart");
6677 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 in case only checking, moved to buttons in TracklengthPanel
6678  if(ConstructPrefDir->GetPrefDirStartElement(0, HLoc, VLoc))
6679  {
6682  SetLevel1Mode(65);
6684  SetLevel2TrackMode(30);
6685  }
6686  Utilities->CallLogPop(48);
6687  return;
6688  }
6689 
6690  else if(Level2TrackMode == DistanceContinuing) // new for extended distances - similar to PrefDirContinuing
6691  // prior to selecting finish element
6692  {
6693  TrainController->LogEvent("mbLeft + DistanceContinuing");
6694 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 in case only checking, moved to buttons in TracklengthPanel
6695  bool FinishElement = false, LeadingPointsAtLastElement = false;
6696  Screen->Cursor = TCursor(-11); // Hourglass;
6697  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(181, 0).HLoc != HLoc) ||
6698  (ConstructPrefDir->GetFixedPrefDirElementAt(182, 0).VLoc != VLoc))
6699  {
6700  // not same as start element
6701  if(ConstructPrefDir->GetNextPrefDirElement(0, HLoc, VLoc, FinishElement))
6702  {
6705  ConstructPrefDir->CalcDistanceAndSpeed(1, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6706  if(FinishElement)
6707  {
6708  TrackLengthPanel->Visible = true;
6709  TrackLengthPanel->SetFocus();
6710  InfoPanel->Visible = true;
6711  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values (overall length), or right click to cancel/truncate";
6712  RestoreAllDefaultLengthsButton->Enabled = true;
6713  ResetDefaultLengthButton->Enabled = true;
6714  LengthOKButton->Enabled = true;
6715  DistanceBox->Text = AnsiString(OverallDistance);
6716  if(OverallSpeedLimit > -1)
6717  {
6718  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6719  }
6720  else
6721  {
6722  SpeedLimitBox->Text = "Mixed";
6723  }
6725  Screen->Cursor = TCursor(-2); // Arrow
6726  Utilities->CallLogPop(1527);
6727  return;
6728  }
6729  else
6730  {
6731  if(!LeadingPointsAtLastElement)
6732  {
6733  TrackLengthPanel->Visible = true;
6734  TrackLengthPanel->SetFocus();
6735  InfoPanel->Visible = true;
6736  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6737  RestoreAllDefaultLengthsButton->Enabled = true;
6738  ResetDefaultLengthButton->Enabled = true;
6739  LengthOKButton->Enabled = true;
6740  DistanceBox->Text = AnsiString(OverallDistance);
6741  if(OverallSpeedLimit > -1)
6742  {
6743  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6744  }
6745  else
6746  {
6747  SpeedLimitBox->Text = "Mixed";
6748  }
6749  // Level2TrackMode = DistanceContinuing;
6750  // SetLevel2TrackMode();
6751  }
6752  else
6753  {
6754  TrackLengthPanel->Visible = true;
6755  TrackLengthPanel->SetFocus();
6756  InfoPanel->Visible = true;
6757  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, need to continue or truncate";
6758  RestoreAllDefaultLengthsButton->Enabled = false;
6759  ResetDefaultLengthButton->Enabled = false;
6760  LengthOKButton->Enabled = false;
6761  // Level2TrackMode = DistanceContinuing;
6762  // SetLevel2TrackMode();
6763  }
6764  }
6765  }
6766  }
6767  else // same as start element
6768  {
6771  SetLevel2TrackMode(54);
6772  Screen->Cursor = TCursor(-2); // Arrow
6773  Utilities->CallLogPop(1713);
6774  return;
6775  }
6777  Screen->Cursor = TCursor(-2); // Arrow
6778  Utilities->CallLogPop(1490);
6779  return;
6780  }
6781 
6782  else if(Level2TrackMode == GapSetting)
6783  {
6784  TrainController->LogEvent("mbLeft + GapSetting");
6785 // ResetChangedFileDataAndCaption(, true); moved to later after 2.7.0 in case can't set it
6786  // HighLightOneGap already called once from SetLevel2TrackMode so have all gap element values set
6787  // & it is highlighted
6788  if(!(Track->FindSetAndDisplayMatchingGap(1, HLoc, VLoc)))
6789  {
6790  Utilities->CallLogPop(50);
6791  return; // true if finds one
6792  }
6793  ResetChangedFileDataAndCaption(11, true); // moved to here after 2.7.0 in case can't set it
6794  InfoPanel->Visible = true;
6795  InfoPanel->Caption = "CONNECTING GAPS: Connecting element selected";
6796  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
6797  Delay(0, 500); // 500 msec delay before next selection requested
6798 
6799  // ClearandRebuildRailway(8);//get rid of gap selections
6800  // need to call this later when new gap displayed, else old gap remains
6801 
6802  // now back to highlighting next gap
6803  // bool LocError = false;
6804  if(!(HighLightOneGap(1, HLoc, VLoc)))
6805  {
6806  // all gaps set
6807  ShowMessage("All gaps set");
6808  if(Level2TrackMode == AddTrack)
6809  {
6811  SetLevel1Mode(66);
6812  SetLevel2TrackMode(31);
6813  }
6814  else
6815  {
6817  SetLevel1Mode(37);
6818  }
6819  ClearandRebuildRailway(9); // get rid of last gap ellipse
6820  Utilities->CallLogPop(51);
6821  return;
6822  }
6823  // here if one gap highlighted so return to user to allow corresponding gap to be selected
6824  // by another call to MainScreenMouseDown
6825  }
6826 
6827  else if(Level2TrackMode == AddText)
6828  {
6829  TrainController->LogEvent("mbLeft + AddText");
6830 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to TextBoxKeyPress in case nothing changed
6831  // X & Y are relative to Display output, but TextBox is placed relative to Form
6832  // if mouse position on first character of an existing piece of text reload it into the editor
6833 
6834  bool TextFoundFlag = false;
6835  int TrueX = 0, TrueY = 0;
6836  AnsiString ExistingText = "";
6838  TFont *ExistingTextFont = new TFont;
6839  int ExistingTextHPos = 0, ExistingTextVPos = 0;
6840  Track->GetTruePositionsFromScreenPos(1, TrueX, TrueY, X, Y);
6841  if(!TextHandler->TextVector.empty())
6842  {
6843  for(TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin(); TextPtr--)
6844  {
6845  if((TrueX >= TextPtr->HPos) && (TrueX < (TextPtr->HPos + abs(TextPtr->Font->Height))) && (TrueY >= TextPtr->VPos) && (TrueY <
6846  (TextPtr->VPos + abs(TextPtr->Font->Height))))
6847  {
6848  ExistingText = TextPtr->TextString;
6849  ExistingTextFont->Assign(TextPtr->Font);
6850  ExistingTextHPos = TextPtr->HPos;
6851  ExistingTextVPos = TextPtr->VPos;
6852  TextFoundFlag = true;
6853  TextHandler->TextErase(9, TrueX, TrueY, ExistingText);
6854  break;
6855  } // if ....
6856 
6857  } // for TextPtr...
6858  } // if !TextVector...
6859 
6860  if(TextFoundFlag)
6861  {
6862  TextBox->Left = ExistingTextHPos + Display->Left() - (Display->DisplayOffsetH * 16) - 3;
6863  TextBox->Top = ExistingTextVPos + Display->Top() - (Display->DisplayOffsetV * 16) - 3;
6864  TextBox->Font->Assign(ExistingTextFont);
6865  Display->SetFont(ExistingTextFont);
6866  Text_X = ExistingTextHPos;
6867  Text_Y = ExistingTextVPos;
6868  }
6869  else
6870  {
6871  TextBox->Left = (TextOrUserGraphicGridVal * div((Display->Left() + X), TextOrUserGraphicGridVal).quot) - 3;
6872  TextBox->Top = (TextOrUserGraphicGridVal * div((Display->Top() + Y), TextOrUserGraphicGridVal).quot) - 3;
6873  TextBox->Font->Assign(Display->GetFont());
6874  Text_X = TextOrUserGraphicGridVal * div(NoOffsetX, TextOrUserGraphicGridVal).quot;
6875  Text_Y = TextOrUserGraphicGridVal * div(NoOffsetY, TextOrUserGraphicGridVal).quot;
6876  }
6877  TextBox->Visible = true;
6878  TextBox->SetFocus();
6879  if(TextFoundFlag)
6880  {
6881  TextBox->Text = ExistingText;
6882  }
6883  else
6884  {
6885  TextBox->Text = "New Text: CR=end, ESC=quit";
6886  }
6887  TextBox->Width = (abs(TextBox->Font->Height) * TextBox->Text.Length() * 0.7);
6888  TextBox->SelectAll();
6889  delete ExistingTextFont;
6890  ClearandRebuildRailway(29); // to remove old text if replaced
6892  Utilities->CallLogPop(1775);
6893  return; // If text input go no further
6894  }
6895 
6897  {
6898  TrainController->LogEvent("mbLeft + MoveTextOrGraphic");
6899 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to later in case nothing found
6900  // int HPosInput;// = X + (Display->DisplayOffsetH * 16);
6901  // int VPosInput;// = Y + (Display->DisplayOffsetV * 16);
6902  // Track->GetTruePositionsFromScreenPos(HPosInput, VPosInput, X, Y);
6903  // StartX = X + (Display->DisplayOffsetH * 16);
6904  // StartY = Y + (Display->DisplayOffsetV * 16);
6907  if(!TextFoundFlag) // give precedence to text
6908  {
6911  {
6912  ResetChangedFileDataAndCaption(13, true); // moved here after 2.7.0 to save only if something found
6913  }
6914  }
6915  else
6916  {
6917  ResetChangedFileDataAndCaption(27, true); // and here
6918  }
6919  Utilities->CallLogPop(53);
6920  return; // if text move selected don't permit anything else
6921  }
6922 
6923  else if(Level2TrackMode == TrackSelecting)
6924  /* When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
6925  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
6926  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
6927  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
6928  selected rectangle.
6929  */
6930  {
6931  TrainController->LogEvent("mbLeft + TrackSelecting");
6932  ClearandRebuildRailway(10); // to get rid of earlier rectangles
6933  SelectStartPair.first = HLoc;
6934  SelectStartPair.second = VLoc;
6935  }
6936 
6937  else if((Level2TrackMode == CopyMoving) || (Level2TrackMode == CutMoving))
6938  /* The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
6939  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
6940  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
6941  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
6942  */
6943  {
6944  TrainController->LogEvent("mbLeft + CopyMoving or CutMoving");
6945 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to later in case don't proceed
6946  if((X < ((SelectBitmapHLoc - Display->DisplayOffsetH) * 16) + 4) ||
6947  (X > ((SelectBitmapHLoc + (SelectBitmap->Width / 16) - Display->DisplayOffsetH) * 16) - 4))
6948  {
6949  SelectPickedUp = false;
6950  Utilities->CallLogPop(54);
6951  return; // within 4 pixels of outside of horizontal area (4 pixels are so can't push selection off edge of screen)
6952  }
6953  if((Y < ((SelectBitmapVLoc - Display->DisplayOffsetV) * 16) + 4) ||
6954  (Y > ((SelectBitmapVLoc + (SelectBitmap->Height / 16) - Display->DisplayOffsetV) * 16) - 4))
6955  {
6956  SelectPickedUp = false;
6957  Utilities->CallLogPop(55);
6958  return; // within 4 pixels of outside of vertical area (4 pixels are so can't push selection off edge of screen)
6959  }
6960  else
6961  {
6962  SelectPickedUp = true;
6963  }
6964  ResetChangedFileDataAndCaption(14, true); // moved here after 2.7.0 in case don't proceed
6967  }
6968 
6970  {
6971  TrainController->LogEvent("mbLeft + != PrefDirContinuing");
6972 // ResetChangedFileDataAndCaption(, false); //moved after 2.7.0 to later in case don't click on element
6973 // RlyFile = false; - don't alter this just for PrefDir changes
6974  if(ConstructPrefDir->GetPrefDirStartElement(1, HLoc, VLoc))
6975  {
6976  ResetChangedFileDataAndCaption(15, false); // moved after 2.7.0 to here
6980  }
6981  Utilities->CallLogPop(56);
6982  return;
6983  }
6984 
6986  {
6987  TrainController->LogEvent("mbLeft + PrefDirContinuing");
6988 // ResetChangedFileDataAndCaption(, false); //moved after 2.7.0 to later in case don't click on element
6989 // RlyFile = false; - don't alter this just for PrefDir changes
6990  bool FinishElement;
6991  Screen->Cursor = TCursor(-11); // Hourglass;
6992  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(183, 0).HLoc != HLoc) ||
6993  (ConstructPrefDir->GetFixedPrefDirElementAt(184, 0).VLoc != VLoc))
6994  {
6995  // not same as start element
6996  if(ConstructPrefDir->GetNextPrefDirElement(1, HLoc, VLoc, FinishElement))
6997  {
6999  ResetChangedFileDataAndCaption(16, false); // moved after 2.7.0 to here
7000  if(FinishElement)
7001  {
7002  ShowMessage("Preferred direction added");
7005  SetLevel1Mode(16);
7006  Screen->Cursor = TCursor(-2); // Arrow
7007  Utilities->CallLogPop(57);
7008  return;
7009  }
7010  else
7011  {
7014  }
7015  // set again since 1st time
7016  // PrefDir vector only had start element & Truncate wasn't enabled, also need
7017  // to do the checks for Loop & End for each element as it is added
7018  }
7019  }
7020  else // same as start element
7021  {
7024  SetLevel1Mode(121);
7025  Screen->Cursor = TCursor(-2); // Arrow
7026  Utilities->CallLogPop(1714);
7027  return;
7028  }
7029  Screen->Cursor = TCursor(-2); // Arrow
7030  Utilities->CallLogPop(58);
7031  return;
7032  }
7033 
7035  {
7036  TrainController->LogEvent("mbLeft + PrefDirSelecting");
7037  ClearandRebuildRailway(56); // to get rid of earlier rectangles
7038  SelectStartPair.first = HLoc;
7039  SelectStartPair.second = VLoc;
7040  }
7041 
7042  else if(Level1Mode == OperMode)
7043  {
7044  if((Level2OperMode == Operating) && CallingOnButton->Down && CallingOnButton->Enabled)
7045  {
7046  TrainController->LogEvent("mbLeft + Operating & CallingOnButton->Down");
7047  int Position;
7048  TTrackElement TrackElement;
7049  if(Track->FindNonPlatformMatch(2, HLoc, VLoc, Position, TrackElement))
7050  {
7051  if(TrackElement.TrackType != SignalPost)
7052  {
7053  CallingOnButton->Down = false;
7054 // InfoPanel->Visible = false; //dropped at v1.3.0, not sure what purpose intended to serve but don't want to lose the info panel as did with this here also added line below to reset
7056  Utilities->CallLogPop(59);
7057  return;
7058  }
7059  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
7060  {
7062  {
7064  x).LeadExitPos] == Position) && (TrackElement.Config[Track->TrackElementAt(429, TrainController->TrainVectorAt(28,
7066  {
7067  // found it!
7068 /*
7069  if(TrackElement.SpeedTag == 68)
7070  {
7071  Display->PlotOutput(0, (HLoc * 16), (VLoc * 16), RailGraphics->bm68CallingOn);
7072  }
7073  if(TrackElement.SpeedTag == 69)
7074  {
7075  Display->PlotOutput(1, (HLoc * 16), (VLoc * 16), RailGraphics->bm69CallingOn);
7076  }
7077  if(TrackElement.SpeedTag == 70)
7078  {
7079  Display->PlotOutput(2, (HLoc * 16), (VLoc * 16), RailGraphics->bm70CallingOn);
7080  }
7081  if(TrackElement.SpeedTag == 71)
7082  {
7083  Display->PlotOutput(3, (HLoc * 16), (VLoc * 16), RailGraphics->bm71CallingOn);
7084  }
7085  if(TrackElement.SpeedTag == 72)
7086  {
7087  Display->PlotOutput(4, (HLoc * 16), (VLoc * 16), RailGraphics->bm72CallingOn);
7088  }
7089  if(TrackElement.SpeedTag == 73)
7090  {
7091  Display->PlotOutput(5, (HLoc * 16), (VLoc * 16), RailGraphics->bm73CallingOn);
7092  }
7093  if(TrackElement.SpeedTag == 74)
7094  {
7095  Display->PlotOutput(6, (HLoc * 16), (VLoc * 16), RailGraphics->bm74CallingOn);
7096  }
7097  if(TrackElement.SpeedTag == 75)
7098  {
7099  Display->PlotOutput(7, (HLoc * 16), (VLoc * 16), RailGraphics->bm75CallingOn);
7100  }
7101 */
7102  Track->TrackElementAt(430, Position).CallingOnSet = true;
7103  Track->PlotSignal(13, Track->TrackElementAt(893, Position), Display);
7104 // added at v 1.3.0 in place of the above to ensure ground signals (as well as others) plot correctly for proceed
7105  // have to call after CallingOnSet becomes true & can't use TrackElement as that still has CallingOnSet false
7106  ClearandRebuildRailway(69); // added at v1.3.0 to replot route on element after PlotSignal above
7109  CallingOnButton->Down = false;
7111 
7112 // set an unrestricted route into the station (just to the first platform) from the stop signal (note that it may be last in an autosigs
7113 // route) but remove any single route elements first (can't reach here if constructing a route), else may try to extend a route that
7114 // has been removed (only a precaution, shouldn't cause any probs whether single route set or not)
7115  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
7116  {
7117  if(AllRoutes->GetFixedRouteAt(192, x).PrefDirSize() == 1)
7118  {
7119  // only allow route element to be removed if not selected for a route start otherwise
7120  // StartSelectionRouteID will be set & will fail at convert
7122  {
7124  AllRoutes->RemoveRouteElement(21, PDE.HLoc, PDE.VLoc, PDE.GetELink());
7125  TrainController->LogEvent("SingleRouteElementRemovedDuringCallon, H = " + AnsiString(PDE.HLoc) + ", V = " +
7126  AnsiString(PDE.VLoc));
7127  }
7128  }
7129  }
7130 
7131 // find the correct entry in CallonVector - i.e. where Position == RouteStartEntry
7132  for(unsigned int x = 0; x < AllRoutes->CallonVector.size(); x++)
7133  {
7134  if(AllRoutes->CallonVector.at(x).RouteStartPosition == Position)
7135  {
7136  // found it
7137  if(!(AllRoutes->CallonVector.at(x).RouteOrPartRouteSet))
7138  // if RouteOrPartRouteSet false then set an unrestricted route into platform
7139  {
7140  bool PointsChanged = false;
7141  IDInt ReqPosRouteID(-1);
7142  TOneRoute *NewRoute = new TOneRoute;
7143  bool CallonTrue = true;
7144  if(NewRoute->GetNonPreferredRouteStartElement(1,
7145  Track->TrackElementAt(841, AllRoutes->CallonVector.at(x).RouteStartPosition).HLoc,
7146  Track->TrackElementAt(842, AllRoutes->CallonVector.at(x).RouteStartPosition).VLoc, CallonTrue))
7147  {
7148  if(NewRoute->GetNextNonPreferredRouteElement(1,
7149  Track->TrackElementAt(843, AllRoutes->CallonVector.at(x).PlatformPosition).HLoc,
7150  Track->TrackElementAt(844, AllRoutes->CallonVector.at(x).PlatformPosition).VLoc, CallonTrue,
7151  ReqPosRouteID, PointsChanged))
7152  {
7153  if(!PointsChanged) // shouldn't be changed, something wrong if true so don't plot route
7154  {
7155  NewRoute->ConvertAndAddNonPreferredRouteSearchVector(3, ReqPosRouteID);
7156  ClearandRebuildRailway(67); // to plot the route (only finds one so won't call repeatedly)
7157  }
7158  }
7159  }
7160  delete NewRoute;
7161  }
7162  }
7163  }
7164 // InfoPanel->Visible = false;
7165  Utilities->CallLogPop(60);
7166  return;
7167  }
7168  }
7169  }
7170  }
7171  CallingOnButton->Down = false;
7173  Utilities->CallLogPop(61);
7174  return;
7175  }
7176 /* get 1st element, first check if selected points, not in existing route, & in RouteNotStarted mode
7177  if so, set all the flash values, Track->PointFlashFlag & start time, then exit for flasher to take over.
7178  If any of above conditions not met then treat as route selection, setting route flasher if
7179  route continuing.
7180 */
7181 
7182  if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // not 'else if' as both may apply
7183  // disallow route setting if paused
7184  {
7185  if(Level2OperMode == PreStart)
7186  {
7187  PointsFlashDuration = 0.0;
7190  }
7191  else
7192  {
7193  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7194  if(TTClockSpeed < 1)
7195  {
7196  TempSpeedVal = TTClockSpeed;
7197  }
7198  PointsFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7201  }
7202  if(RouteMode == RouteNotStarted)
7203  {
7204  TrainController->LogEvent("mbLeft + RouteNotStarted");
7205  int Position;
7206  TTrackElement TrackElement;
7207  if(Track->FindNonPlatformMatch(3, HLoc, VLoc, Position, TrackElement))
7208  {
7209  if((TrackElement.TrackType == Points) && !(AllRoutes->TrackIsInARoute(1, Position, 0))
7211  // Flash selected points & changeover if appropriate
7212  // need !Track->PointFlashFlag to prevent another point being selected while another is flashing, & !Track->RouteFlashFlag
7213  // to ensure user only does one thing at a time
7214  {
7215  if(TrackElement.TrainIDOnElement > -1)
7216  {
7217  TrainController->StopTTClockMessage(1, "Can't change points under a train!");
7218  Utilities->CallLogPop(62);
7219  return;
7220  }
7221  PointFlash->SetScreenHVSource(1, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7222 
7223 /*
7224  This used to try to allow any linked trailing edges to cause both points to change, but no good if
7225  there are two adjacent crossovers, where both trailing edges are linked to two different points.
7226  The wrong link might be chosen. Also doubtful if applying a strict order of checks would work, since
7227  may be obscure configurations that would be wrong. This function bypasses the MatchingPoint check, which
7228  ensures that there are no obscure links. Hence better to stick with original.
7229 
7230  //check if trailing edge linked to another point trailing edge
7231  int DivergingPosition = TrackElement.Conn[1];
7232  TTrackElement DivergingElement = Track->TrackElementAt(431, TrackElement.Conn[1]);
7233  DivergingPointVectorPosition = -1;
7234  if((DivergingElement.TrackType == Points) &&
7235  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
7236  {
7237  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
7238  {
7239  ShowMessage("Linked points Locked");
7240  }
7241  else DivergingPointVectorPosition = DivergingPosition;
7242  }
7243  else
7244  {
7245  DivergingPosition = TrackElement.Conn[3];
7246  DivergingElement = Track->TrackElementAt(432, TrackElement.Conn[3]);
7247  if((DivergingElement.TrackType == Points) &&
7248  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
7249  {
7250  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
7251  {
7252  ShowMessage("Linked points locked");
7253  }
7254  else DivergingPointVectorPosition = DivergingPosition;
7255  }
7256  }
7257  Track->PointFlashFlag = true;
7258  PointFlashVectorPosition = Position;
7259  PointFlashStartTime = TrainController->TTClockTime;
7260  [close curly bracket - if include it matches earlier non-commented one!]
7261 */
7262  TTrackElement DivergingElement = Track->TrackElementAt(433, TrackElement.Conn[3]);
7263  int DivergingPosition = TrackElement.Conn[3];
7264  if((DivergingElement.TrackType == Points) && (DivergingElement.Conn[3] == Position) && (Track->MatchingPoint(1, Position,
7265  DivergingPosition))) // full match inc same attributes
7266  {
7267  if(AllRoutes->TrackIsInARoute(4, DivergingPosition, 0))
7268  {
7269  TrainController->StopTTClockMessage(2, "Linked points locked");
7270  }
7271  else
7272  {
7273  Track->PointFlashFlag = true;
7274  PointFlashVectorPosition = Position;
7275  DivergingPointVectorPosition = DivergingPosition;
7277  }
7278  }
7279  else // no matching point, just change this point
7280  {
7281  Track->PointFlashFlag = true;
7282  PointFlashVectorPosition = Position;
7285  }
7286  }
7287 
7288  else if(Track->IsLCAtHV(59, HLoc, VLoc) && !Track->PointFlashFlag && !Track->RouteFlashFlag)
7289  // level crossing added at v2.6.0 to allow manual LC changing
7290  {
7291  if(Track->GetInactiveTrackElementFromTrackMap(5, HLoc, VLoc).Attribute != 2) // 2 = LC changing state, can't click if changing
7292  {
7293  Track->LCChangeFlag = true;
7294  bool TrainPresent = false;
7295  if(Track->IsLCBarrierDownAtHV(4, HLoc, VLoc)) // if true then may be able to raise barriers
7296  {
7297  // first need to identify the LC in the BarriersDownVector
7298  int BDVectorPos = -1;
7299  if(Track->AnyLinkedBarrierDownVectorManual(1, HLoc, VLoc, BDVectorPos)) // looking for same position & manually closed
7300  {
7301  // this largely copied from ClockTimer2
7303  Track->BarriersDownVector.at(BDVectorPos).VLoc, ConstructRoute->SearchVector, TrainPresent))
7304  // returns true for route set or being set or train, and TrainPresent true if train on LC
7305  {
7306  TTrack::TActiveLevelCrossing CLC = Track->BarriersDownVector.at(BDVectorPos);
7307  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
7308  TDateTime TempExcessLCDownTime;
7309  if(Track->BarriersDownVector.at(BDVectorPos).ReducedTimePenalty)
7310  // this set in ClockTimer2, relies on train being on LC for >= 1 second
7311  {
7312  // get the 3 mins allowance - hard to imagine will pass in less than a second!
7313  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
7314  }
7315  else
7316  {
7317  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
7318  }
7319  if(TempExcessLCDownTime > TDateTime(0))
7320  {
7321  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
7322  }
7323  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
7326  Track->SetLinkedLevelCrossingBarrierAttributes(7, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
7327  Track->ChangingLCVector.push_back(CLC);
7328  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + BDVectorPos);
7329  }
7330  }
7331  }
7332  else // lowering
7333  {
7334  // this largely copied from SetLCChangeValues
7335  TTrack::TActiveLevelCrossing ALC; // constructor sets ReducedTimePenalty to false
7336  ALC.HLoc = HLoc;
7337  ALC.VLoc = VLoc;
7339  ALC.BaseElementSpeedTag = TrackElement.SpeedTag;
7342  ALC.TypeOfRoute = 2;
7343  Track->SetLinkedManualLCs(0, HLoc, VLoc);
7344 // this sets all linked LC ConsecSignals values to 2 for manually lowered - differs from SetLCChangeValues which uses the route type
7345  Track->SetLinkedLevelCrossingBarrierAttributes(6, HLoc, VLoc, 2); // set attr to 2 for changing state
7346  Track->ChangingLCVector.push_back(ALC);
7348  {
7349  AnsiString Message =
7350  AnsiString("This will open the level crossing manually (it will show in green).\n\nA manually opened"
7351  " level crossing must be manually closed, and as soon as possible to avoid time penalties.\n\n" "This message will not be shown again."
7352  );
7353  TrainController->StopTTClockMessage(93, Message);
7355  }
7356  }
7357  }
7358  }
7359  else // route start
7360  {
7361  if(AutoSigsFlag)
7362  {
7363  AutoRouteStartMarker->SetScreenHVSource(2, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7365  }
7366  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
7367  {
7368  SigRouteStartMarker->SetScreenHVSource(3, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7370  }
7371  else
7372  {
7373  NonSigRouteStartMarker->SetScreenHVSource(4, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7375  }
7376  if(PreferredRoute)
7377  {
7378  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7379  // another route building
7380  {
7381  ConstructRoute->ClearRoute(); // in case not empty though should be
7383  {
7384  if(AutoSigsFlag)
7385  {
7387  }
7388  else
7389  {
7391  }
7393  InfoPanel->Visible = true;
7394  if(Level2OperMode == PreStart)
7395  {
7396  InfoPanel->Caption = "PRE-START: Select next route location";
7397  }
7398  else
7399  {
7400  InfoPanel->Caption = "OPERATING: Select next route location";
7401  }
7402  }
7403  }
7404  Utilities->CallLogPop(63);
7405  return;
7406  }
7407  else // nonpreferred route
7408  {
7409  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7410  // another route building
7411  {
7412  ConstructRoute->ClearRoute(); // in case not empty though should be
7413  bool CallonFalse = false;
7414  if(ConstructRoute->GetNonPreferredRouteStartElement(0, HLoc, VLoc, CallonFalse))
7415  {
7418  InfoPanel->Visible = true;
7419  if(Level2OperMode == PreStart)
7420  {
7421  InfoPanel->Caption = "PRE-START: Select next route location";
7422  }
7423  else
7424  {
7425  InfoPanel->Caption = "OPERATING: Select next route location";
7426  }
7427  }
7428  }
7429  Utilities->CallLogPop(64);
7430  return;
7431  } // NonPreferred route
7432 
7433  } // TrackType != Points
7434 
7435  } // if(Track->FindNonPlatformMatch(HLoc, VLoc, Position, TrackElement))
7436 
7437  } // if(RouteMode == RouteNotStarted)
7438  else // RouteContinuing
7439  {
7440  TrainController->LogEvent("mbLeft + RouteContinuing");
7441  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7444  AutoRouteStartMarker->PlotOriginal(14, Display); // if overlay not plotted will ignore
7445  SigRouteStartMarker->PlotOriginal(15, Display); // if overlay not plotted will ignore
7446  NonSigRouteStartMarker->PlotOriginal(16, Display); // if overlay not plotted will ignore
7447  Screen->Cursor = TCursor(-11); // Hourglass - also set to an hourglass when flashing, after found required
7448  // element, but this sets it to an hourglass while searching
7449  bool PointsChanged = false;
7450  if(PreferredRoute)
7451  {
7452  // route added to AllRoutes in GetNextRouteElement if valid
7453  // int ReqPosRouteNumber;
7455  ConstructRoute->ReqPosRouteID, PointsChanged))
7456  {
7457  Track->RouteFlashFlag = true;
7458  PreferredRouteFlag = true;
7459  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7460  if(TTClockSpeed < 1)
7461  {
7462  TempSpeedVal = TTClockSpeed;
7463  }
7464  if(Level2OperMode == PreStart)
7465  {
7466  RouteFlashDuration = 0.0;
7467  }
7468  else if(PointsChanged)
7469  {
7470  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7471  }
7472  else
7473  {
7474  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7475  }
7476  ConstructRoute->SetRouteFlashValues(1, AutoSigsFlag, true); // true for PrefDirRoute
7478  }
7479  else
7480  {
7482  }
7483  Screen->Cursor = TCursor(-2); // Arrow
7484  TrainController->BaseTime = TDateTime::CurrentDateTime();
7486  Utilities->CallLogPop(65);
7487  return;
7488  }
7489  else
7490  {
7491  bool CallonFalse = false;
7492  if(ConstructRoute->GetNextNonPreferredRouteElement(0, HLoc, VLoc, CallonFalse, ConstructRoute->ReqPosRouteID, PointsChanged))
7493  {
7494  Track->RouteFlashFlag = true;
7495  PreferredRouteFlag = false;
7496  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7497  if(TTClockSpeed < 1)
7498  {
7499  TempSpeedVal = TTClockSpeed;
7500  }
7501  if(Level2OperMode == PreStart)
7502  {
7503  RouteFlashDuration = 0.0;
7504  }
7505  else if(PointsChanged)
7506  {
7507  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7508  }
7509  else
7510  {
7511  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7512  }
7513  ConstructRoute->SetRouteFlashValues(2, false, false);
7515  }
7516  else
7517  {
7519  }
7520  }
7521  TrainController->BaseTime = TDateTime::CurrentDateTime();
7523  Screen->Cursor = TCursor(-2); // Arrow
7524  }
7525  Utilities->CallLogPop(66);
7526  return;
7527  }
7528  }
7529  Utilities->CallLogPop(68);
7530  }
7531  catch(const Exception &e)
7532  {
7533  ErrorLog(20, e.Message);
7534  }
7535 }
7536 
7537 // ---------------------------------------------------------------------------
7538 
7539 void TInterface::MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
7540 // ZoomOut mode
7541 {
7542 // NB: DisplayZoomOutOffsetH & V take account of the Min & Max H & V values so don't need these again
7543  try
7544  {
7545  TrainController->LogEvent("MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) +
7547  "," + AnsiString(Y));
7548  if(Button != mbLeft)
7549  {
7550  // this routine new at v2.1.0. Allows railway moving for zoom-out mode
7553  WholeRailwayMoving = true;
7554  Screen->Cursor = TCursor(-22); // Four arrows;
7555  }
7556  else
7557  {
7558  InfoPanel->Visible = false; // reset infopanel in case not set later
7559  InfoPanel->Caption = "";
7560  int HRounding, VRounding;
7561  int TruePosH = (X / 4) + Display->DisplayZoomOutOffsetH;
7562  int TruePosV = (Y / 4) + Display->DisplayZoomOutOffsetV;
7563  // find nearest screen centre - from 30 to 210 horiz & from 18 to 126 vert
7564  if(TruePosH < 0)
7565  {
7566  HRounding = -(Utilities->ScreenElementWidth / 4);
7567  }
7568  else
7569  {
7570  HRounding = (Utilities->ScreenElementWidth / 4);
7571  }
7572  int CentreH = (((TruePosH + HRounding) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2));
7573  while((CentreH - Track->GetHLocMax()) >= (Utilities->ScreenElementWidth / 2))
7574  {
7575  CentreH -= (Utilities->ScreenElementWidth / 2);
7576  }
7577  while((Track->GetHLocMin() - CentreH) >= (Utilities->ScreenElementWidth / 2))
7578  {
7579  CentreH += (Utilities->ScreenElementWidth / 2);
7580  }
7581  if(TruePosV < 0)
7582  {
7583  VRounding = -(Utilities->ScreenElementHeight / 4);
7584  }
7585  else
7586  {
7587  VRounding = (Utilities->ScreenElementHeight / 4);
7588  }
7589  int CentreV = (((TruePosV + VRounding) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2));
7590  while((CentreV - Track->GetVLocMax()) >= (Utilities->ScreenElementHeight / 2))
7591  {
7592  CentreV -= (Utilities->ScreenElementHeight / 2);
7593  }
7594  while((Track->GetVLocMin() - CentreV) >= (Utilities->ScreenElementHeight / 2))
7595  {
7596  CentreV += (Utilities->ScreenElementHeight / 2);
7597  }
7598  Display->DisplayOffsetH = CentreH - (Utilities->ScreenElementWidth / 2);
7600 
7601  TLevel2OperMode TempLevel2OperMode = Level2OperMode;
7602  if(Level1Mode == BaseMode)
7603  {
7604  SetLevel1Mode(17);
7605  }
7606  else if(Level1Mode == TrackMode)
7607  {
7608  // set edit menu items
7610  PreventGapOffsetResetting = true; // when return from zoom by clicking screen don't force a return to the
7611  // displayed gap, user wants to display the clicked area
7612  SetLevel2TrackMode(32); // revert to earlier track mode from zoom
7613  PreventGapOffsetResetting = false;
7614  }
7615  else if(Level1Mode == PrefDirMode)
7616  {
7618  {
7619  SetLevel2PrefDirMode(3); // revert to earlier PrefDir mode from zoom
7620  }
7621  else
7622  {
7623  SetLevel1Mode(33); // if PrefDirSelecting revert to normap PrefDirMode
7624  }
7625  }
7626  // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
7627  // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
7628  else if(Level1Mode == TimetableMode)
7629  {
7630  InfoPanel->Visible = false;
7631  }
7632  // Not OperMode or RestartSessionOperMode as that resets the performance file
7633  else if(TempLevel2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
7634  {
7635  OperateButton->Enabled = true;
7636  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
7637  ExitOperationButton->Enabled = true;
7639  }
7640  else if(TempLevel2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
7641  {
7642  OperateButton->Enabled = true;
7643  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7644  ExitOperationButton->Enabled = true;
7645  TTClockAdjButton->Enabled = true;
7648  }
7649  else if(TempLevel2OperMode == PreStart)
7650  {
7651  OperateButton->Enabled = true;
7652  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7653  ExitOperationButton->Enabled = true;
7654  TTClockAdjButton->Enabled = true;
7656  }
7657  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
7660  }
7661  Utilities->CallLogPop(69);
7662  }
7663  catch(const Exception &e)
7664  {
7665  ErrorLog(21, e.Message);
7666  }
7667 }
7668 
7669 // ---------------------------------------------------------------------------
7670 
7671 void __fastcall TInterface::MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
7672 {
7673  try
7674  {
7675  // TrainController->LogEvent("MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y)); //dropped at v0.6, too many events
7676  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y));
7677 
7678  if(!mbLeftDown && WholeRailwayMoving) // new at v2.1.0
7679  {
7680  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7682  if(X < 0)
7683  {
7684  X = 0; // ensure pointer stays within display area
7685  }
7686  if(X > (MainScreen->Width - 1))
7687  {
7688  X = MainScreen->Width - 1;
7689  }
7690  if(Y < 0)
7691  {
7692  Y = 0;
7693  }
7694  if(Y > (MainScreen->Height - 1))
7695  {
7696  Y = MainScreen->Height - 1;
7697  }
7698  if(!Display->ZoomOutFlag)
7699  {
7700  int StartOffsetX = (X - StartWholeRailwayMoveHPos) % 16;
7701  int StartOffsetY = (Y - StartWholeRailwayMoveVPos) % 16;
7702  if((abs(X - StartWholeRailwayMoveHPos) >= 16) || (abs(Y - StartWholeRailwayMoveVPos) >= 16))
7703  {
7704  int NewH = X - StartWholeRailwayMoveHPos;
7705  int NewV = Y - StartWholeRailwayMoveVPos;
7706  Display->DisplayOffsetH -= NewH / 16;
7707  Display->DisplayOffsetV -= NewV / 16;
7708  StartWholeRailwayMoveHPos = X - StartOffsetX;
7709  StartWholeRailwayMoveVPos = Y - StartOffsetY;
7712  {
7714  }
7715  }
7716  }
7717 
7718  else
7719  {
7720  int StartZOffsetX = (X - StartWholeRailwayMoveHPos) % 4;
7721  int StartZOffsetY = (Y - StartWholeRailwayMoveVPos) % 4;
7722  if((abs(X - StartWholeRailwayMoveHPos) >= 4) || (abs(Y - StartWholeRailwayMoveVPos) >= 4))
7723  {
7724  int NewH = X - StartWholeRailwayMoveHPos;
7725  int NewV = Y - StartWholeRailwayMoveVPos;
7726  Display->DisplayZoomOutOffsetH -= NewH / 4;
7727  Display->DisplayZoomOutOffsetV -= NewV / 4;
7728  StartWholeRailwayMoveHPos = X - StartZOffsetX;
7729  StartWholeRailwayMoveVPos = Y - StartZOffsetY;
7730  Display->ClearDisplay(10);
7732  }
7733  }
7734  TrainController->BaseTime = TDateTime::CurrentDateTime();
7736  }
7737 
7738  else if(mbLeftDown)
7739  {
7741  /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7742  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7743  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7744  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7745  selected rectangle.
7746  [New] At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7747  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7748  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7749  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7750  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7751  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7752  the selection.
7753  */
7754  {
7755  if(!MMoveTrackSelFlag)
7756  {
7757  TrainController->LogEvent("MouseMove + TrackSelecting");
7758  MMoveTrackSelFlag = true;
7759  }
7760  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7761  Track->GetTrackLocsFromScreenPos(2, CurrentHLoc, CurrentVLoc, X, Y);
7762  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7763  // rightmost point and the VLoc value of the bottommost point
7764  if(CurrentHLoc >= StartHLoc)
7765  {
7766  CurrentHLoc++;
7767  }
7768  else
7769  {
7770  StartHLoc++;
7771  }
7772  if(CurrentVLoc >= StartVLoc)
7773  {
7774  CurrentVLoc++;
7775  }
7776  else
7777  {
7778  StartVLoc++;
7779  }
7780  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7781  {
7783  }
7784  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7785  {
7787  }
7788  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7789  {
7790  CurrentHLoc = Display->DisplayOffsetH;
7791  }
7792  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7793  {
7794  CurrentVLoc = Display->DisplayOffsetV;
7795  }
7796  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7797  ClearandRebuildRailway(14); // to clear earlier rectangles
7798  Display->PlotDashedRect(0, TempRect);
7799  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
7800  }
7801 
7803  {
7804  if(!MMovePrefDirSelFlag)
7805  {
7806  TrainController->LogEvent("MouseMove + PrefDirSelecting");
7807  MMovePrefDirSelFlag = true;
7808  }
7809 
7810  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7811  Track->GetTrackLocsFromScreenPos(5, CurrentHLoc, CurrentVLoc, X, Y);
7812  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7813  // rightmost point and the VLoc value of the bottommost point
7814  if(CurrentHLoc >= StartHLoc)
7815  {
7816  CurrentHLoc++;
7817  }
7818  else
7819  {
7820  StartHLoc++;
7821  }
7822  if(CurrentVLoc >= StartVLoc)
7823  {
7824  CurrentVLoc++;
7825  }
7826  else
7827  {
7828  StartVLoc++;
7829  }
7830  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7831  {
7833  }
7834  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7835  {
7837  }
7838  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7839  {
7840  CurrentHLoc = Display->DisplayOffsetH;
7841  }
7842  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7843  {
7844  CurrentVLoc = Display->DisplayOffsetV;
7845  }
7846  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7847  ClearandRebuildRailway(57); // to clear earlier rectangles
7848  Display->PlotDashedRect(2, TempRect);
7849  Display->Update(); // need to keep this since Update() not called for PlotSmallOutput as too slow
7850  }
7851 
7853  /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7854  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7855  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7856  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7857  [New] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7858  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7859  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7860  occupies. Clearand... is called finally to clear earlier selection displays.
7861  */
7862  {
7864  {
7865  TrainController->LogEvent("MouseMove + Copy or CutMoving & SelectPickedUp");
7867  }
7868  if(X < 0)
7869  {
7870  X = 0; // ensure pointer stays within display area
7871  }
7872  if(X > (MainScreen->Width - 1))
7873  {
7874  X = MainScreen->Width - 1;
7875  }
7876  if(Y < 0)
7877  {
7878  Y = 0;
7879  }
7880  if(Y > (MainScreen->Height - 1))
7881  {
7882  Y = MainScreen->Height - 1;
7883  }
7886  ClearandRebuildRailway(15); // plots SelectBitmap at the position given by NewSelectBitmapHLoc & ...VLoc
7887  }
7888 
7890  {
7892  {
7893  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & TextFoundFlag");
7895  }
7897  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7899  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7900 
7901  TextHandler->TextPtrAt(26, TextItem)->HPos = NewHPos;
7902  TextHandler->TextPtrAt(27, TextItem)->VPos = NewVPos;
7904  }
7905 
7907  {
7909  {
7910  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & UserGraphicFoundFlag");
7912  }
7914  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7916  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7917 
7921  }
7922  }
7923  Utilities->CallLogPop(70);
7924  }
7925  catch(const Exception &e)
7926  {
7927  ErrorLog(22, e.Message);
7928  }
7929 }
7930 
7931 // ---------------------------------------------------------------------------
7932 void __fastcall TInterface::MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
7933 {
7934 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7935  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7936  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7937  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7938  selected rectangle.
7939  [Repeated from MouseMove] - At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7940  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7941  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7942  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7943  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7944  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7945  the selection.
7946  [New] This function can take some time so an hourglass cursor is displayed. The rectangle is fully defined, so the final screen X & Y
7947  values are translated into HLoc & VLoc values (wrt whole railway) and SelectEndPair set using them. The rectangle can be defined in any
7948  direction, so the end points may be before or after the starting points for both horizontal and vertical directions. Therefore the
7949  rectangle that will be used subsequently - SelectRect - is defined from SelectStart and SelectEnd allowing for any direction. Screen
7950  limits are set as during MouseMove, and a dashed edge drawn as before. Then a check is made to see if the final rectangle has any area,
7951  and if not 'Select' mode is kept and the function ends so that a new rectangle can be drawn, otherwise new menu items Cut, Copy & Delete,
7952  are enabled. Now the SelectBitmap is made ready by filling with white prior to the track bitmaps being copied. If this isn't done the
7953  track bitmaps are loaded from the top left hand corner and the rest becomes black - not what is wanted! The SelectVector (defined in
7954  TrackUnit) is then loaded with the elements enclosed by the rectangle, top to bottom and left to right, active track elements first then
7955  inactive track elements. Empty squares are ignored as are default (erased) elements. Now the SelectVector is read and the corresponding
7956  element bitmaps transferred to SelectBitmap in the appropriate positions, then a dashed border added. Finally the cursor is changed back
7957  to an arrow.
7958 */
7959  try
7960  {
7961  TrainController->LogEvent("MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7962  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7963  WholeRailwayMoving = false; // added at v2.1.0
7964  Screen->Cursor = TCursor(-2); // Arrow; (to reset from four arrows when moving) added at v2.1.0
7965  MMoveTrackSelFlag = false;
7966  MMovePrefDirSelFlag = false;
7970 
7972  {
7973  TrainController->LogEvent("MouseUp + TrackSelecting + mbLeftDown");
7974  Screen->Cursor = TCursor(-11); // Hourglass;
7975  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7976  Track->GetTrackLocsFromScreenPos(3, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7977 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7978 // rightmost point and the VLoc value of the bottommost point
7979  if(EndHLoc >= StartHLoc)
7980  {
7981  EndHLoc++;
7982  }
7983  else
7984  {
7985  StartHLoc++;
7986  }
7987  if(EndVLoc >= StartVLoc)
7988  {
7989  EndVLoc++;
7990  }
7991  else
7992  {
7993  StartVLoc++;
7994  }
7995  if(StartHLoc >= EndHLoc)
7996  {
7997  SelectRect.left = EndHLoc;
7998  SelectRect.right = StartHLoc;
7999  }
8000  else
8001  {
8002  SelectRect.left = StartHLoc;
8003  SelectRect.right = EndHLoc;
8004  }
8005  if(StartVLoc >= EndVLoc)
8006  {
8007  SelectRect.top = EndVLoc;
8008  SelectRect.bottom = StartVLoc;
8009  }
8010  else
8011  {
8012  SelectRect.top = StartVLoc;
8013  SelectRect.bottom = EndVLoc;
8014  }
8016  {
8018  }
8020  {
8022  }
8023  if(SelectRect.left - Display->DisplayOffsetH < 0)
8024  {
8026  }
8027  if(SelectRect.top - Display->DisplayOffsetV < 0)
8028  {
8030  }
8031  Level2TrackMode = AddTrack; // Level1Mode must be TrackMode
8032  SetLevel2TrackMode(69); // add all track elements so area can be filled with an element, must come before PlotDashedRect as calls Clearand...
8033  Level2TrackMode = TrackSelecting; // reset from AddTrack
8037  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
8038  {
8039  SelectionValid = false;
8041  mbLeftDown = false;
8042  Screen->Cursor = TCursor(-2); // Arrow;
8043  Utilities->CallLogPop(71);
8044  return; // no rectangle
8045  }
8046  else
8047  {
8048  ReselectMenuItem->Enabled = false;
8049  CutMenuItem->Enabled = true;
8050  CopyMenuItem->Enabled = true;
8051  FlipMenuItem->Enabled = true;
8052  MirrorMenuItem->Enabled = true;
8053  RotRightMenuItem->Enabled = true;
8054  RotLeftMenuItem->Enabled = true;
8055  RotateMenuItem->Enabled = true;
8056 
8057 // PasteWithAttributesMenuItem->Enabled = false; //new menu item for v2.2.0 only enabled after cutting (dropped at 2.4.0 as all pastes are with attributes)
8058  DeleteMenuItem->Enabled = true;
8059  if(Track->IsTrackFinished())
8060  {
8061  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
8062  }
8063  else
8064  {
8065  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
8066  }
8067  SelectBiDirPrefDirsMenuItem->Visible = false;
8068  CheckPrefDirConflictsMenuItem->Visible = false;
8069  CancelSelectionMenuItem->Enabled = true;
8070  // set SelectBitmap
8071  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
8072  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
8073 
8074  // fill it with transparent white (i.e. use Draw) else graphics all plot from top left hand corner
8075  for(int H = 0; H < (SelectBitmap->Width) / 16; H++)
8076  {
8077  for(int V = 0; V < (SelectBitmap->Height) / 16; V++)
8078  {
8079  SelectBitmap->Canvas->Draw(H * 16, V * 16, RailGraphics->bmSolidBgnd);
8080  // NB in above if use bmTransparent it ISN'T transparent, but if use the non-transparent bmSolidBgnd it IS transparent
8081  // presumably superimposing a transparent bitmap onto a transparent bitmap makes the result non-transparent!
8082  }
8083  }
8084 
8086  TTrackElement TempElement; // default element
8087  bool FoundFlag;
8088  //store active elements
8089  for(int x = SelectRect.left; x < SelectRect.right; x++)
8090  {
8091  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8092  {
8093  int ATVecPos = Track->GetVectorPositionFromTrackMap(2, x, y, FoundFlag);
8094  if(FoundFlag)
8095  {
8096  TempElement = Track->TrackElementAt(440, ATVecPos);
8097  if(TempElement.SpeedTag > 0)
8098  {
8099  Track->SelectPush(TempElement); // don't store erase elements
8100  }
8101  }
8102  }
8103  }
8104  // now store inactive elements
8105  for(int x = SelectRect.left; x < SelectRect.right; x++)
8106  {
8107  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8108  {
8109  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(2, x, y, FoundFlag);
8110  if(FoundFlag)
8111  {
8112  TempElement = Track->InactiveTrackElementAt(30, IATVecPair.first);
8113  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
8114  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
8115  {
8116  TempElement = Track->InactiveTrackElementAt(31, IATVecPair.second);
8117  Track->SelectPush(TempElement);
8118  }
8119  }
8120  }
8121  }
8122 
8123  //store preferred directions //added at v2.9.0
8124  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
8125  TPrefDirElement TempPrefDirElement;
8127  for(int x = SelectRect.left; x < SelectRect.right; x++)
8128  {
8129  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8130  {
8131  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(11, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
8132  if(FoundFlag)
8133  {
8134  if(PrefDirPos0 > -1)
8135  {
8136  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(2, PrefDirPos0);
8137  SelectPrefDir->ExternalStorePrefDirElement(6, TempPrefDirElement);
8138  }
8139  if(PrefDirPos1 > -1)
8140  {
8141  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(3, PrefDirPos1);
8142  SelectPrefDir->ExternalStorePrefDirElement(7, TempPrefDirElement);
8143  }
8144  if(PrefDirPos2 > -1)
8145  {
8146  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(4, PrefDirPos2);
8147  SelectPrefDir->ExternalStorePrefDirElement(8, TempPrefDirElement);
8148  }
8149  if(PrefDirPos3 > -1)
8150  {
8151  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(5, PrefDirPos3);
8152  SelectPrefDir->ExternalStorePrefDirElement(9, TempPrefDirElement);
8153  }
8154  }
8155  }
8156  }
8157 
8158  // store text items
8159  int LowSelectHPos = SelectRect.left * 16;
8160  int HighSelectHPos = SelectRect.right * 16;
8161  int LowSelectVPos = SelectRect.top * 16;
8162  int HighSelectVPos = SelectRect.bottom * 16;
8163  TextHandler->SelectTextVector.clear();
8164  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
8165  {
8166  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
8167  {
8168  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
8169  HighSelectVPos))
8170  {
8171  // have to create a new TextItem in order to create a new Font object
8172  // BUT: only create new items where they don't appear as named location names
8173  // in SelectVector, since those names shouldn't be copied or pasted.
8174  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
8175  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
8176  bool SelectVectorNamedElement = false;
8177  AnsiString SelectTextString; // new at v2.2.0
8178  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
8179  {
8180  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
8181  {
8182  SelectVectorNamedElement = true;
8183  break;
8184  }
8185  }
8186  if(SelectVectorNamedElement) // changed at v2.2.0
8187  {
8188  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
8189  }
8190  else // new at v2.2.0
8191  {
8192  SelectTextString = TextPtr->TextString;
8193  }
8194  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
8195  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
8196  }
8197  }
8198  }
8199  // store graphic items, but first clear SelectGraphicVector
8200  Track->SelectGraphicVector.clear();
8201  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
8202  {
8203  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
8204  UserGraphicPtr++)
8205  {
8206  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) &&
8207  (UserGraphicPtr->VPos >= LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
8208  {
8209  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
8210  }
8211  }
8212  }
8213 // new method - direct copying of existing selection so text included
8214  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
8215  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
8216  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
8217  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
8218  SelectionValid = true;
8219  }
8220  Screen->Cursor = TCursor(-2); // Arrow;
8221  }
8222 
8224  {
8225  TrainController->LogEvent("MouseUp + PrefDirSelecting + mbLeftDown");
8226  Screen->Cursor = TCursor(-11); // Hourglass;
8227 
8228  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
8229  Track->GetTrackLocsFromScreenPos(6, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
8230 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
8231 // rightmost point and the VLoc value of the bottommost point
8232  if(EndHLoc >= StartHLoc)
8233  {
8234  EndHLoc++;
8235  }
8236  else
8237  {
8238  StartHLoc++;
8239  }
8240  if(EndVLoc >= StartVLoc)
8241  {
8242  EndVLoc++;
8243  }
8244  else
8245  {
8246  StartVLoc++;
8247  }
8248  if(StartHLoc >= EndHLoc)
8249  {
8250  SelectRect.left = EndHLoc;
8251  SelectRect.right = StartHLoc;
8252  }
8253  else
8254  {
8255  SelectRect.left = StartHLoc;
8256  SelectRect.right = EndHLoc;
8257  }
8258  if(StartVLoc >= EndVLoc)
8259  {
8260  SelectRect.top = EndVLoc;
8261  SelectRect.bottom = StartVLoc;
8262  }
8263  else
8264  {
8265  SelectRect.top = StartVLoc;
8266  SelectRect.bottom = EndVLoc;
8267  }
8269  {
8271  }
8273  {
8275  }
8276  if(SelectRect.left - Display->DisplayOffsetH < 0)
8277  {
8279  }
8280  if(SelectRect.top - Display->DisplayOffsetV < 0)
8281  {
8283  }
8287  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
8288  {
8290  mbLeftDown = false;
8291  Screen->Cursor = TCursor(-2); // Arrow;
8292  Utilities->CallLogPop(1551);
8293  return; // no rectangle
8294  }
8295  else
8296  {
8297  SelectBiDirPrefDirsMenuItem->Enabled = true;
8298  CheckPrefDirConflictsMenuItem->Enabled = false;
8299  CancelSelectionMenuItem->Enabled = true;
8300  // don't need SelectBitmap for PrefDir selection
8301 
8302  // store active elements in Track->SelectVector, ignore inactive elements
8303  // clear the vector first
8305  TTrackElement TempElement; // default element
8306  bool FoundFlag;
8307  for(int x = SelectRect.left; x < SelectRect.right; x++)
8308  {
8309  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8310  {
8311  int ATVecPos = Track->GetVectorPositionFromTrackMap(43, x, y, FoundFlag);
8312  if(FoundFlag)
8313  {
8314  TempElement = Track->TrackElementAt(729, ATVecPos);
8315  if(TempElement.SpeedTag > 0)
8316  {
8317  Track->SelectPush(TempElement); // don't store erase elements
8318  }
8319  }
8320  }
8321  }
8322  }
8323  Screen->Cursor = TCursor(-2); // Arrow;
8324  }
8325 
8327  /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
8328  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
8329  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
8330  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
8331  [Repeated from MouseMove] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
8332  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
8333  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
8334  occupies. Clearand... is called finally to clear earlier selection displays.
8335  [New] - The only action here is to transfer the values of NewSelectBitmapHLoc & VLoc to SelectBitmapHLoc & VLoc so that the selection
8336  stays in the same position (Clearand... checks whether the mouse is moving (both mbLeftDown & SelectPickedUp true) or stopped (either
8337  mbLeftDown or SelectPickedUp false) and uses NewSelectBitmapHLoc & VLoc or SelectBitmapHLoc & SelectBitmapVLoc respectively.
8338  */
8339  {
8340  TrainController->LogEvent("MouseUp + Copy or CutMoving + mbLeftDown + SelectPickedUp");
8343  }
8344  mbLeftDown = false;
8345  Track->CalcHLocMinEtc(11);
8346  Utilities->CallLogPop(72);
8347  }
8348  catch(const Exception &e)
8349  {
8350  ErrorLog(23, e.Message);
8351  }
8352 }
8353 
8354 // ---------------------------------------------------------------------------
8355 
8356 void __fastcall TInterface::MasterClockTimer(TObject *Sender)
8357 {
8358  try
8359  {
8360  // don't call LogEvent here as would occur too often
8361  // have to allow in zoomout mode
8362  if(ErrorLogCalledFlag)
8363  {
8364  return; // don't continue after an error
8365  }
8366  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MasterClockTimer");
8367  // put counter outside Clock2 as that may be missed
8368  LCResetCounter++;
8369 // this checks LCs every 20 clock ticks (1 sec) & raises barriers if no route & no train present, to avoid delays due to too frequent calls
8370  if(LCResetCounter > 19)
8371  {
8372  LCResetCounter = 0;
8373  }
8375  if(WarningFlashCount > 4)
8376  {
8377  WarningFlashCount = 0;
8378  }
8379  if(WarningFlashCount == 0)
8380  {
8382  }
8383  if(Utilities->CallLog.size() > 50) // use CTRL ALT 2 to see CallLogSize as program operates
8384  {
8385  throw Exception("Warning - Utilities->CallLog contains more than 50 items"); // check before clock stopped
8386  }
8388  // stopped during 'Paused', when modal windows appear - Popup menu & ShowMessage, and at other times
8389  {
8390  // RestartTime is TTClockTime when operation pauses (timetable start time initially),
8391  // BaseTime is CurrentDateTime() when operation restarts
8392 
8393 // clock speed multiplier
8394  double RealTimeDouble = double(TDateTime::CurrentDateTime() - TrainController->BaseTime);
8395  TrainController->TTClockTime = TDateTime(TTClockSpeed * RealTimeDouble) + TrainController->RestartTime;
8396 // TrainController->TTClockTime = TDateTime::CurrentDateTime() - TrainController->BaseTime + TrainController->RestartTime;
8397  }
8398 
8399 /*
8400 //elapsed time investigations - lose ~20% of ticks when nothing loaded & ~30% for a busy session
8401 //even lose ~20% without ClockTimer2. but this is when running in IDE, try outside - exactly the same.
8402 //see https://www.tek-tips.com/viewthread.cfm?qid=672717 - TTimer is very inaccurate, and the minimum interval is about 56ms because
8403 //of the PC clock frequency which is about 18Hz, so it always runs slow at short intervals. In light of this the 30% loss for a busy
8404 //session isn't too bad, it represents about 12% loss in reality.
8405 
8406 //Set breakpoint at int x = 4, load railway, start timer with Alt Ctrl 4 then check elapsed time when stops
8407 //no need to reload between checks,
8408 
8409  if(ElapsedTimeTestFunctionStart) //set in test function CTRL ALT 4
8410  {
8411  Start = double(GetTime()) * 86400; //secs
8412  ElapsedTimerRunning = true;
8413  TotalTicks = 0;
8414  ElapsedTimeTestFunctionStart = false;
8415  }
8416 
8417  if(ElapsedTimerRunning && TotalTicks < 100) //should take 5secs at 50ms, it's about 6.25secs with nothing loaded
8418  {
8419  TotalTicks++;
8420  }
8421  else if(ElapsedTimerRunning && TotalTicks >= 100)
8422  {
8423  End = double(GetTime()) * 86400;
8424  ElapsedTimerRunning = false;
8425 
8426  ElapsedTime = End - Start; //secs
8427 
8428  int x = 4; //breakpoint
8429  } //TrainController->TrainVector.size() <- Ctrl copy & paste into debugger window to examine
8430 //end of elapsed time code
8431 */
8433  {
8434  Utilities->CallLogPop(774);
8435  return;
8436  }
8437  Utilities->Clock2Stopped = true; // don't allow overlapping calls
8438  ClockTimer2(0);
8439  Utilities->Clock2Stopped = false;
8440  Utilities->CallLogPop(73);
8441 
8442  }
8443  catch(const Exception &e)
8444  {
8445  ErrorLog(24, e.Message);
8446  }
8447 }
8448 
8449 // ---------------------------------------------------------------------------
8450 
8451 void TInterface::ClockTimer2(int Caller)
8452 {
8453 // called every 50mSec
8454  try
8455  {
8456  // have to allow in zoomout mode
8457  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClockTimer2");
8458 
8459  // dropped at 2.0.0 because RestoreFocusPanel->SetFocus(); hides the help screen
8460  // If a button holds focus then all that is needed is to click the screen and the arrow keys work correctly
8461 
8462 /* Dropped when new .chm help file introduced at v2.0.0 - this hid it after ~20ms. Replaced by a new section in
8463  MainScreenMouseDown where focus restored to screen when click anywhere on screen, allowing navigation keys to
8464  move screen when clicked if focus had been captured by another panel when these keys just cycle through the panel buttons
8465 
8466  bool FocusRestoreAllowedFlag = true; //added at v1.3.0
8467 
8468  if(TextBox->Focused() || DistanceBox->Focused() || SpeedLimitBox->Focused() || LocationNameTextBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
8469  SpeedEditBox2->Focused() || LocationNameComboBox->Focused() || AddSubMinsBox->Focused() || SpeedEditBox->Focused() || PowerEditBox->Focused() || OneEntryTimetableMemo->Focused() ||
8470  AddPrefDirButton->Focused()) //Added at v1.3.0. If any of these has focus then they keep it until they release it. AddPrefDirButton is included as it should keep focus
8471  FocusRestoreAllowedFlag = false; //when it has it - eases the setting of PrefDirs, also this button becomes disabled after use so focus returns to Interface naturally
8472 
8473  if(!Focused() && FocusRestoreAllowedFlag && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0)) //condition added at v1.3.0 to ensure focus returned to
8474  //Interface (so arrow keys work to move screen) & not left at any of the buttons or other Windows controls
8475  //include the Windows API functions to test that the mouse buttons are not down (strictly only need left but user may have mapped the left onto the right so test both) - if not
8476  //tested then don't always respond to button clicks on navigation and other buttons because the focus can be grabbed back from the button by RestoreFocusPanel before the button
8477  //can respond (takes about 200mSec from click to response) a delay is also included to doubly avoid the button losing focus as above
8478  {
8479  ClockTimer2Count++; //doesn't matter what value it starts at on first use, it will soon revert to 0
8480  if(ClockTimer2Count > 10) ClockTimer2Count = 0; //half second delay
8481  if(ClockTimer2Count == 0)
8482  {
8483  RestoreFocusPanel->Visible = true;
8484  RestoreFocusPanel->Enabled = true;
8485  RestoreFocusPanel->BringToFront();
8486  //RestoreFocusPanel->SetFocus(); //to remove focus from anything else
8487  RestoreFocusPanel->Enabled = false; //to remove focus from RestoreFocusPanel & return it to Interface
8488  RestoreFocusPanel->Visible = false;
8489  }
8490  }
8491  else ClockTimer2Count = 0; //reset to 0 so ensure full delay occurs before RestoreFocusPanel grabs focus from anything else
8492 */
8493  CallLogTickerLabel->Caption = Utilities->CallLog.size(); // diagnostic test function to ensure all CallLogs are popped - visibility
8494  // toggled by 'Ctrl Alt 2' when Interface form has focus
8495 
8496  // set current time
8497  TDateTime Now = TrainController->TTClockTime;
8498 
8499 
8500  if(!OAListBox->MouseInClient) // added at v2.7.0 to reset this flag whenever mouse not in OAListBox
8501  {
8503  }
8504  if(!ClipboardChecked)
8505  {
8506  if((Level1Mode == TrackMode) && !SelectionValid && (ClpBrdValid != "RlyClpBrd_Cut") && (ClpBrdValid != "RlyClpBrdCopy"))
8507  // reset the menu for the new app (when !SelectionValid) & don't keep resetting when ClpBrdValid
8508  //before 2.10.0 one '&' was missing before '(ClpBrdValid != "RlyClpBrd_Cut")' making it into an address which would always be > 0 i.e.true
8509  {
8510  SetTrackModeEditMenu(2); // to reset the menu in case select a new app for pasting
8511  ClipboardChecked = true;
8512  }
8513  }
8514 // Update Displayed Clock - resets to 0 at 96hours
8516 
8517 //timers
8521  {
8523  }
8524  if(OperatorActionPanel->Visible)
8525  {
8527  }
8530  {
8531  TrainController->OpActionPanelHintDelayCounter = 60; // new at v2.2.0
8532  }
8533  TrainController->RandomFailureCounter++; // new at v2.4.0 counts up for 53 seconds then resets
8535  {
8537  }
8538 
8539 //multiplayer functions - disabled at v2.12.0 as not needed yet
8540 /*
8541  PlayerFiveSecondTimer++; // new for multiplayer for player send cycle
8542  if(PlayerFiveSecondTimer >= 100)
8543  {
8544  PlayerFiveSecondTimer = 0;
8545  }
8546 
8547  PlayerOneSecondTimer++; // new for multiplayer for player cancel
8548  if(PlayerOneSecondTimer >= 20)
8549  {
8550  PlayerOneSecondTimer = 0;
8551  }
8552 
8553  HostMultiplayInProgressFlag = false;
8554  PlayerMultiplayInProgressFlag = false;
8555  if(MultiplayerHostPanel->Visible || HostInSessionFlag)
8556  {
8557  HostMultiplayInProgressFlag = true;
8558  }
8559  else if(MultiplayerPlayerPanel->Visible || PlayerInSessionFlag)
8560  {
8561  PlayerMultiplayInProgressFlag = true;
8562  }
8563 
8564  if(Level2OperMode == PreStart)
8565  {
8566  if(!MultiplayerHostPanel->Visible && !MultiplayerPlayerPanel->Visible)
8567  {
8568  MultiplayerMenu->Enabled = true;
8569  MultiplayerHostSessionMenuItem->Enabled = true;
8570  SaveMultiplayerSessionMenuItem->Enabled = false;
8571  EndSimulationMenuItem->Enabled = false;
8572  ShowHideStringGridMenuItem->Enabled = false;
8573  JoinMultiplayerSessionMenuItem->Enabled = true;
8574  ExitSimulationMenuItem->Enabled = false;
8575  }
8576  else
8577  {
8578  MultiplayerMenu->Enabled = false;
8579  }
8580  }
8581 
8582  if(HostInSessionFlag && !PlayerInSessionFlag)
8583  {
8584 
8585  MultiplayerMenu->Enabled = true;
8586  MultiplayerHostSessionMenuItem->Enabled = false;
8587  SaveMultiplayerSessionMenuItem->Enabled = true;
8588  EndSimulationMenuItem->Enabled = true;
8589  ShowHideStringGridMenuItem->Enabled = true;
8590  JoinMultiplayerSessionMenuItem->Enabled = false;
8591  ExitSimulationMenuItem->Enabled = false;
8592  }
8593  else if(!HostInSessionFlag && PlayerInSessionFlag)
8594  {
8595 
8596  MultiplayerMenu->Enabled = true;
8597  MultiplayerHostSessionMenuItem->Enabled = false;
8598  SaveMultiplayerSessionMenuItem->Enabled = false;
8599  EndSimulationMenuItem->Enabled = false;
8600  ShowHideStringGridMenuItem->Enabled = false;
8601  JoinMultiplayerSessionMenuItem->Enabled = false;
8602  ExitSimulationMenuItem->Enabled = true;
8603  }
8604 
8605  if(HostMultiplayInProgressFlag)
8606  {
8607  HostHandshakingActions();
8608  }
8609  else if(PlayerMultiplayInProgressFlag)
8610  {
8611  PlayerHandshakingActions();
8612  }
8613 */
8614 //end of multiplayer functions
8615 
8616 // Below added at v2.1.0 to ensure WholeRailwayMoving flag reset when not moving (when rh mouse button up) as sometimes misses
8617 // MouseUp events, probably due to a clash between a moving event and a mouse up event. Note that checks that both mouse buttons are up because
8618 // function only checks the physical buttons, not the logical buttons. Most sig bit of return value set form key down.
8619  if(WholeRailwayMoving && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0))
8620  {
8621  WholeRailwayMoving = false;
8622  Screen->Cursor = TCursor(-2); // Arrow
8623  }
8624 // save session if required
8625  if(SaveSessionFlag)
8626  {
8627  SaveSession(0);
8628  SaveSessionFlag = false;
8629  }
8630 // load session if required
8631  if(LoadSessionFlag)
8632  {
8633  if(ClearEverything(3))
8634  {
8635  LoadSession(0);
8636  }
8637  LoadSessionFlag = false;
8638  }
8639 // check if any LCs need barriers raising
8640 
8642  {
8644  {
8645  for(int x = Track->BarriersDownVector.size() - 1; x >= 0; x--) // iterate downwards because erase element
8646  {
8647  bool TrainPresent = false;
8649  Track->BarriersDownVector.at(x).VLoc, ConstructRoute->SearchVector, TrainPresent)) // returns true for route (set or being set) or train, and TrainPresent true if train on LC
8650  {
8651  if(TrainPresent)
8652  {
8653  Track->BarriersDownVector.at(x).ReducedTimePenalty = true;
8654 // to allow 3 mins before time penalty starts to clock up, if no train passes then no time allowance
8655  }
8656  }
8657  else
8658  {
8659  if(Track->BarriersDownVector.at(x).TypeOfRoute != 2) // added at v2.6.0 for manual LC operation
8660  {
8661  Track->LCChangeFlag = true;
8663  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
8664  TDateTime TempExcessLCDownTime;
8665  if(Track->BarriersDownVector.at(x).ReducedTimePenalty)
8666  {
8667  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
8668  }
8669  else
8670  {
8671  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
8672  }
8673  if(TempExcessLCDownTime > TDateTime(0))
8674  {
8675  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
8676  }
8677  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
8680  Track->SetLinkedLevelCrossingBarrierAttributes(0, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
8681  Track->ChangingLCVector.push_back(CLC);
8682  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + x);
8683  }
8684  }
8685  }
8686  }
8687  }
8688 // clear LCChangeFlag if no LCs changing
8689  if(Track->ChangingLCVector.empty())
8690  {
8691  Track->LCChangeFlag = false;
8692  }
8693 // remove any single route elements if operating, but only if not constructing a route, else if extending the single route
8694 // element it may be removed prior to conversion & cause an error
8695 
8696 // note that if a train enters at a continuation and a signal is next but one to the continuation then the route element at that
8697 // signal won't be removed because the train's LagElement is still -1 and trains only remove route elements when LagElement is > -1.
8698 // This also means that a preferred route can't be cancelled as it's under a train, but it's probably not worth adding a patch just for
8699 // this, it shouldn't interfere with operation.
8701  {
8702  bool ElementRemovedFlag = false; // introduced at v0.6 to avoid calling Clearand.... multiple times
8703  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
8704  {
8705  if(AllRoutes->GetFixedRouteAt(187, x).PrefDirSize() == 1)
8706  {
8707  // only allow route element to be removed if not selected for a route start otherwise StartSelectionRouteID will be
8708  // set & will fail at convert
8710  {
8712  // also don't remove if it links two automatic signal routes (reported by Daniel Gill for Darlington via discord on 13/12/20)
8713  // added at v2.6.1
8714  // note that a train will still remove the route element when it reaches it because of the 3rd condition below, but it will be removed when the train
8715  // is half on the preceding element rather than fully on it, in other cases the train has to be fully on the element because the route only becomes a
8716  // single element at that stage
8717  unsigned int LinkFromTVNumber = Track->TrackElementAt(1007, PDE.GetTrackVectorPosition()).Conn[PDE.GetELinkPos()];
8718  unsigned int LinkToTVNumber = Track->TrackElementAt(1008, PDE.GetTrackVectorPosition()).Conn[PDE.GetXLinkPos()];
8719  int RouteNumber1, RouteNumber2, TrainID; // not used
8720  if((AllRoutes->GetRouteTypeAndNumber(37, LinkFromTVNumber, PDE.GetELinkPos(), RouteNumber1) != TAllRoutes::AutoSigsRoute) ||
8721  (AllRoutes->GetRouteTypeAndNumber(38, LinkToTVNumber, PDE.GetXLinkPos(), RouteNumber2) != TAllRoutes::AutoSigsRoute) ||
8722  (Track->TrackElementAt(1009, LinkFromTVNumber).TrainIDOnElement > -1))
8723  // don't need to test for it being a bridge as then LinkFromTVNumber can't be
8724  // an autosigs route
8725  {
8726  AllRoutes->RemoveRouteElement(20, PDE.HLoc, PDE.VLoc, PDE.GetELink());
8727  ElementRemovedFlag = true;
8728  TrainController->LogEvent("SingleRouteElementRemoved, H = " + AnsiString(PDE.HLoc) + ", V = " + AnsiString(PDE.VLoc));
8729  }
8730  }
8731  }
8732  }
8733  if(!Display->ZoomOutFlag && ElementRemovedFlag)
8734  {
8736  }
8737  // if zoomed out ignore, will display correctly when zoom in
8738  // if leave the Zoomout condition out then the zoom out will spontaneously cancel and the track won't display because
8739  // PlotOutput returns if zoomed out, and the zoom out flag isn't reset until the end of Clearand.....
8740  // this was moved outside the for.. next.. loop in v0.6 as it could be called multiple times and slowed down operation (noticeable with a fast clock)
8741  }
8742 
8743 // stop clock if hover over a warning
8744  bool WH1 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog1->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog1->Width + OutputLog1->Left))
8745  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog1->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog1->Height + OutputLog1->Top))
8746  && OutputLog1->Caption != "";
8747  bool WH2 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog2->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog2->Width + OutputLog2->Left))
8748  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog2->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog2->Height + OutputLog2->Top))
8749  && OutputLog2->Caption != "";
8750  bool WH3 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog3->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog3->Width + OutputLog3->Left))
8751  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog3->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog3->Height + OutputLog3->Top))
8752  && OutputLog3->Caption != "";
8753  bool WH4 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog4->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog4->Width + OutputLog4->Left))
8754  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog4->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog4->Height + OutputLog4->Top))
8755  && OutputLog4->Caption != "";
8756  bool WH5 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog5->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog5->Width + OutputLog5->Left))
8757  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog5->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog5->Height + OutputLog5->Top))
8758  && OutputLog5->Caption != "";
8759  bool WH6 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog6->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog6->Width + OutputLog6->Left))
8760  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog6->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog6->Height + OutputLog6->Top))
8761  && OutputLog6->Caption != "";
8762  bool WH7 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog7->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog7->Width + OutputLog7->Left))
8763  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog7->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog7->Height + OutputLog7->Top))
8764  && OutputLog7->Caption != "";
8765  bool WH8 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog8->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog8->Width + OutputLog8->Left))
8766  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog8->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog8->Height + OutputLog8->Top))
8767  && OutputLog8->Caption != "";
8768  bool WH9 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog9->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog9->Width + OutputLog9->Left))
8769  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog9->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog9->Height + OutputLog9->Top))
8770  && OutputLog9->Caption != "";
8771  bool WH10 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog10->Left) &&
8772  (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog10->Width + OutputLog10->Left)) && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog10->Top) &&
8773  (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog10->Height + OutputLog10->Top)) && OutputLog10->Caption != "";
8774 
8775  if(WH1 || WH2 || WH3 || WH4 || WH5 || WH6 || WH7 || WH8 || WH9 || WH10 || SkipTTActionsListBox->Visible)
8776  {
8777  if(!WarningHover)
8778  {
8779  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
8781  WarningHover = true;
8782  }
8783  }
8784  else if(WarningHover)
8785  {
8786  WarningHover = false;
8787  TrainController->BaseTime = TDateTime::CurrentDateTime();
8789  }
8790 // development panel - visibility toggled by 'Ctrl Alt 3' when Interface form has focus
8791  if(DevelopmentPanel->Visible)
8792  {
8793  int Position;
8794  TTrackElement TrackElement;
8795  AnsiString Type[15] =
8796  {
8797  "Simple", "Crossover", "Points", "Buffers", "Bridge", "SignalPost", "Continuation", "Platform", "GapJump", "FootCrossing", "Unused", "Concourse",
8798  "Parapet", "NamedNonStationLocation", "Erase"
8799  };
8800 
8801  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
8802  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
8803  int HLoc, VLoc;
8804  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
8805  DevelopmentPanel->Caption = CurDir + " " + MouseStr;
8806  Track->GetTrackLocsFromScreenPos(7, HLoc, VLoc, ScreenX, ScreenY);
8807  if(Track->FindNonPlatformMatch(1, HLoc, VLoc, Position, TrackElement))
8808  {
8809  DevelopmentPanel->Caption = MouseStr + "; TVPos: " + AnsiString(Position) + "; H: " + AnsiString(HLoc) + "; V: " + AnsiString(VLoc) +
8810  "; SpTg: " + AnsiString(TrackElement.SpeedTag) + "; Type: " + Type[TrackElement.TrackType] + "; Att: " + AnsiString(TrackElement.Attribute)
8811  + "; TrID: " + AnsiString(TrackElement.TrainIDOnElement) + "; TrID01: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos01) +
8812  "; TrID23: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos23) + "; " + TrackElement.LocationName + "; " +
8813  TrackElement.ActiveTrackElementName;
8814 // + "; OAHintCtr: " + TrainController->OpActionPanelHintDelayCounter;
8815  }
8816  else
8817  {//below used in elapsed time investigations
8818 // DevelopmentPanel->Caption = FormatFloat("#####00.000", (ElapsedTime * 3600 * 24)) + " " + AnsiString(TotalTicks);
8819  }
8820  }
8821  if(Level1Mode == TimetableMode)
8822  {
8823 /* These are for Shift Key shortcuts. Unless 'Click()' execution occurs after the key is pressed Windows stores the key until after any code is executed then selects
8824 the timetable entry that begins with the letter corresponding to the key. See DevHistory.txt for the version at v2.5.0 for details.
8825 
8826 First make sure the selected entry is the Highlighted entry, but only if both mouse buttons are up, to make sure AllEntriesTTListBoxMouseUp runs first or TopIndex
8827 likely to be set to the wrong position since when ...Selected... runs it sets TopIndex accordingly. Then when ...MouseUp runs it will use the wrong value and select
8828 the entry that the mouse is now on rather than the one that was chosen.
8829 Later addition: Set member variable AllEntriesTTListBox->TopIndex here if any flag set so when Copy or any other key function runs the top index is correct
8830 */
8831  if((GetKeyState(VK_LBUTTON) >= 0) && (GetKeyState(VK_RBUTTON) >= 0) && (TTCurrentEntryPtr > 0))
8832  // high order bit set to 1 when button down, so arithmetically it is negative
8833  {
8834  // TTCurrentEntryPtr == 0 when create a timetable
8835  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
8836  }
8837  if(AnyTTKeyFlagSet()) // true if any of the below flags set
8838  {
8839  AllEntriesTTListBox->TopIndex = AllEntriesTTListBoxTopPosition; // reset it to the value before the key press changes it (see FormKeyDown)
8840  }
8842  {
8843  PreviousTTEntryButton->Click();
8844  SetTopIndex(0);
8845  PreviousTTEntryKeyFlag = false;
8846  }
8847  else if(NextTTEntryKeyFlag)
8848  {
8849  NextTTEntryButton->Click();
8850  SetTopIndex(1);
8851  NextTTEntryKeyFlag = false;
8852  }
8853  else if(MoveTTEntryUpKeyFlag)
8854  {
8855  MoveTTEntryUpButton->Click();
8856  SetTopIndex(2);
8857  MoveTTEntryUpKeyFlag = false;
8858  }
8859  else if(MoveTTEntryDownKeyFlag)
8860  {
8861  MoveTTEntryDownButton->Click();
8862  SetTopIndex(3);
8863  MoveTTEntryDownKeyFlag = false;
8864  }
8865  else if(CopyTTEntryKeyFlag)
8866  {
8867  CopyTTEntryButton->Click();
8868  SetTopIndex(4);
8869  CopyTTEntryKeyFlag = false;
8870  }
8871  else if(CutTTEntryKeyFlag)
8872  {
8873  CutTTEntryButton->Click();
8874  SetTopIndex(5);
8875  CutTTEntryKeyFlag = false;
8876  }
8877  else if(PasteTTEntryKeyFlag)
8878  {
8879  PasteTTEntryButton->Click();
8880  SetTopIndex(6);
8881  PasteTTEntryKeyFlag = false;
8882  }
8883  else if(DeleteTTEntryKeyFlag)
8884  {
8885  DeleteTTEntryButton->Click();
8886  SetTopIndex(7);
8887  DeleteTTEntryKeyFlag = false;
8888  }
8889  else if(NewTTEntryKeyFlag)
8890  {
8891  NewTTEntryButton->Click();
8892  SetTopIndex(8);
8893  NewTTEntryKeyFlag = false;
8894  }
8895  else if(AZOrderKeyFlag)
8896  {
8897  AZOrderButton->Click();
8898  SetTopIndex(9);
8899  AZOrderKeyFlag = false;
8900  }
8902  {
8903  TTServiceSyntaxCheckButton->Click();
8904  SetTopIndex(12);
8906  }
8907  else if(ValidateTimetableKeyFlag)
8908  {
8909  ValidateTimetableButton->Click();
8910  SetTopIndex(13);
8911  ValidateTimetableKeyFlag = false;
8912  }
8913  else if(SaveTTKeyFlag)
8914  {
8915  SaveTTButton->Click();
8916  SetTopIndex(14);
8917  SaveTTKeyFlag = false;
8918  }
8919  else if(SaveTTAsKeyFlag)
8920  {
8921  SaveTTAsButton->Click();
8922  SetTopIndex(15);
8923  SaveTTAsKeyFlag = false;
8924  }
8925  else if(RestoreTTKeyFlag)
8926  {
8927  RestoreTTButton->Click();
8928  SetTopIndex(16);
8929  RestoreTTKeyFlag = false;
8930  }
8931  else if(ExportTTKeyFlag)
8932  {
8933  ExportTTButton->Click();
8934  SetTopIndex(17);
8935  ExportTTKeyFlag = false;
8936  }
8937  else if(ConflictAnalysisKeyFlag)
8938  {
8939  ConflictAnalysisButton->Click();
8940  SetTopIndex(18);
8941  ConflictAnalysisKeyFlag = false;
8942  }
8943 // highlight timetable entry if in tt mode (have to call this regularly so will scroll with the listbox)
8944  if(!TimetableEditVector.empty() && (TTCurrentEntryPtr > 0))
8945  {
8947  }
8948  else
8949  {
8951  }
8952  }
8953 // set cursor
8955  {
8956  if(!TempCursorSet)
8957  {
8958  TempCursor = Screen->Cursor;
8959  TempCursorSet = true;
8960  }
8961  Screen->Cursor = TCursor(-11); // Hourglass
8962  }
8963  else
8964  {
8965  if(TempCursorSet)
8966  {
8967  Screen->Cursor = TempCursor;
8968  TempCursorSet = false;
8969  }
8970  }
8971  if(Level2OperMode == Operating)
8972  {
8973  TrainController->Operate(0); // ensure this called AFTER the single element route removal to ensure any single elements removed
8974  // prior to CallingOnAllowed being called (in UpdateTrain) as that sets a route from the stop signal
8976  {
8977  UpdateOperatorActionPanel(0); // new at v2.2.0 to update panel when train OpTimeToAct updated (updated earlier)
8978  }
8979  TrainController->SignallerTrainRemovedOnAutoSigsRoute = false; // added at v1.3.0 to ensure doesn't persist beyond one call
8980  }
8981  else if((Level2OperMode == Paused) || (Level2OperMode == PreStart)) // added at v2.5.0 to show actions due after a session file reloaded
8982  { // modified at v2.10.0 to add PreStart
8983  THVShortPair ExitPair;
8984  ExitPair.first = -1;
8985  ExitPair.second = -1;
8987  {
8988  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
8989  {
8990  float LastTimeToExit = TrainController->TrainVectorAt(78, x).TimeToExit;
8991  TrainController->TrainVectorAt(73, x).OpTimeToAct = TrainController->TrainVectorAt(74, x).CalcTimeToAct(1, LastTimeToExit, ExitPair);
8992  TrainController->TrainVectorAt(79, x).TimeToExit = LastTimeToExit; //this was updated in CalcTimeToAct
8993  TrainController->TrainVectorAt(80, x).ExitPair = ExitPair;
8994  }
8997  }
8999  {
9001  }
9002  }
9003 
9004  // plot trains in ZoomOut mode & flash trains where attention needed alternately on & off at each call
9005 // by examining Flash
9006  if((Level1Mode == OperMode) && (Display->ZoomOutFlag))
9007  {
9009  }
9010 //deal with any manual LCs with barriers down in zoomout mode - these flash as reminder that need to re-open
9011 
9013  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
9014  {
9015  if((Track->BarriersDownVector.at(x).BarrierState == TTrack::Down) && (Track->BarriersDownVector.at(x).TypeOfRoute == 2))
9016  {
9017  //manual crossing down, but maybe a route across it
9018  bool TrainPresent; //not used outside function
9020  ConstructRoute->SearchVector, TrainPresent)) //no warning raised if a route or train present
9021  {
9024  {
9026  RailGraphics->smLC, Display); //smLC
9027  }
9028  else if((WarningFlashCount == 0) && !WarningFlash && Display->ZoomOutFlag)
9029  {
9031  RailGraphics->smSolidBgnd, Display); //SMOrange
9032  }
9033  }
9034  }
9035  }
9036 
9037 // Deal with any flashing graphics
9039  {
9040  FlashingGraphics(0, Now); // only call when WarningFlash changes
9041  if(Level1Mode == OperMode)
9042  {
9043  if(WarningFlash)
9044  {
9046  {
9047  CrashImage->Visible = true;
9048  }
9050  {
9051  DerailImage->Visible = true;
9052  }
9054  {
9055  SPADImage->Visible = true;
9056  }
9058  {
9059  TrainFailedImage->Visible = true;
9060  }
9062  {
9063  CallOnImage->Visible = true;
9064  }
9066  {
9067  SignalStopImage->Visible = true;
9068  }
9070  {
9071  BufferAttentionImage->Visible = true;
9072  }
9073  if(ManualLCDownAttentionWarning) //added at v2.9.0
9074  {
9075  ManualLCDownImage->Visible = true;
9076  }
9077  }
9078  else
9079  {
9080  CrashImage->Visible = false;
9081  DerailImage->Visible = false;
9082  SPADImage->Visible = false;
9083  TrainFailedImage->Visible = false;
9084  CallOnImage->Visible = false;
9085  SignalStopImage->Visible = false;
9086  BufferAttentionImage->Visible = false;
9087  ManualLCDownImage->Visible = false;
9088  }
9089  }
9090  else
9091  {
9092  CrashImage->Visible = false;
9093  DerailImage->Visible = false;
9094  SPADImage->Visible = false;
9095  TrainFailedImage->Visible = false;
9096  CallOnImage->Visible = false;
9097  SignalStopImage->Visible = false;
9098  BufferAttentionImage->Visible = false;
9100  }
9101  } // if(WarningFlashCount == 0)
9102 
9103  // set buttons etc as appropriate
9105  // if forced route cancellation flag set redisplay to clear the cancelled route
9107  {
9109  AllRoutes->RebuildRailwayFlag = false;
9110  }
9111  // deal with approach locking
9113  // deal with ContinuationAutoSigList
9115  // FloatingLabel function
9116  if((TrackInfoOnOffMenuItem->Caption == "Hide") || (TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") ||
9117  (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable"))
9118  {
9119  TrackTrainFloat(0);
9120  }
9121  else
9122  {
9123  FloatingPanel->Visible = false;
9124  }
9125  // PerformanceLog check function
9126 /*
9127  if(IsPerformancePanelObscuringFloatingLabel(0) && (ShowPerformancePanel))
9128  {
9129  PerformancePanel->Visible = false;
9130  }
9131  else
9132  {
9133 */
9135  {
9136  PerformancePanel->Visible = true;
9137  }
9138  else
9139  {
9140  PerformancePanel->Visible = false;
9141  }
9143  {
9144  OperatorActionPanel->Visible = true;
9145  }
9146  else
9147  {
9148  OperatorActionPanel->Visible = false;
9149  }
9150 // }
9151 
9152  // check if a moving train is present on a route-under-construction start element & cancel it if so
9153  if(RouteMode == RouteContinuing)
9154  {
9155  bool FoundFlag;
9156  int RouteStartVecPos;
9157  if(AutoSigsFlag)
9158  {
9160  FoundFlag);
9161  }
9162  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
9163  {
9164  RouteStartVecPos = Track->GetVectorPositionFromTrackMap(8, (SigRouteStartMarker->GetHPos()) / 16, (SigRouteStartMarker->GetVPos()) / 16,
9165  FoundFlag);
9166  }
9167  else
9168  {
9170  FoundFlag);
9171  }
9172  if(FoundFlag && (RouteStartVecPos > -1))
9173  {
9174  TTrackElement TrackElement = Track->TrackElementAt(485, RouteStartVecPos);
9175  if(TrackElement.TrainIDOnElement > -1)
9176  {
9177  if(!(TrainController->TrainVectorAtIdent(2, TrackElement.TrainIDOnElement).Stopped()))
9178  {
9180  // replot train as above erases the front element of the train
9182  }
9183  }
9184  }
9185  }
9186  Utilities->CallLogPop(81);
9187  }
9188  catch(const EIdException &e) //non-error catch
9189 //if no response from peer then get a 'connection reset by peer' message which isn't valid
9190  {
9191 // ShowMessage(EIdExceptionSource + " " + e.Message); //<--temporary - remove this message eventually
9192  Utilities->CallLogPop(2406);
9193  }
9194  catch(const Exception &e)
9195  {
9196  ErrorLog(25, e.Message);
9197  }
9198 }
9199 
9200 // ---------------------------------------------------------------------------
9201 
9202 void __fastcall TInterface::CallingOnButtonClick(TObject *Sender)
9203 {
9204  try
9205  {
9206  TrainController->LogEvent("CallingOnButtonClick");
9207  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CallingOnButtonClick");
9208  if(CallingOnButton->Down)
9209  {
9210  // CallingOnButton->Down = true;
9211  InfoPanel->Visible = true;
9212  InfoPanel->Caption = "CALLING ON: Select signal for call on";
9213  }
9214  else
9215  {
9216  // CallingOnButton->Down = false;
9218  }
9219  AutoRouteStartMarker->PlotOriginal(29, Display); // if overlay not plotted will ignore
9220  SigRouteStartMarker->PlotOriginal(30, Display); // if overlay not plotted will ignore
9221  NonSigRouteStartMarker->PlotOriginal(31, Display); // if overlay not plotted will ignore
9222  CallingOnButton->Enabled = false;
9223 // added at v1.3.0 to ensure doesn't retain focus - will be re-enabled during ClockTimer2 (in SetSaveMenuAndButtons) if required
9224  Utilities->CallLogPop(82);
9225  }
9226  catch(const Exception &e)
9227  {
9228  ErrorLog(26, e.Message);
9229  }
9230 }
9231 
9232 // ---------------------------------------------------------------------------
9233 void __fastcall TInterface::ScreenLeftButtonClick(TObject *Sender)
9234 {
9235  try
9236  {
9237  // have to allow in zoomout mode
9238  TrainController->LogEvent("ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9239  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9240  Screen->Cursor = TCursor(-11); // Hourglass;
9241  ScreenLeftButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9242  if(!Display->ZoomOutFlag)
9243  {
9244  if(CtrlKey)
9245  {
9246  Display->DisplayOffsetH -= 2;
9247  }
9248  else if(ShiftKey)
9249  {
9251  }
9252  else
9253  {
9255  }
9258  {
9260  }
9261  }
9262  else
9263  {
9264  if(CtrlKey)
9265  {
9267  }
9268  else if(ShiftKey)
9269  {
9271  }
9272  else
9273  {
9275  }
9276  Display->ClearDisplay(0);
9279  {
9280  Track->PlotSmallRedGap(0);
9281  }
9282  }
9283  ScreenLeftButton->Enabled = true;
9284  Screen->Cursor = TCursor(-2); // Arrow
9285  Utilities->CallLogPop(83);
9286  }
9287  catch(const Exception &e)
9288  {
9289  ErrorLog(27, e.Message);
9290  }
9291 }
9292 // ---------------------------------------------------------------------------
9293 
9294 void __fastcall TInterface::ScreenRightButtonClick(TObject *Sender)
9295 {
9296  try
9297  {
9298  // have to allow in zoomout mode
9299  TrainController->LogEvent("ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9300  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9301  Screen->Cursor = TCursor(-11); // Hourglass;
9302  ScreenRightButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9303  if(!Display->ZoomOutFlag)
9304  {
9305  if(CtrlKey)
9306  {
9307  Display->DisplayOffsetH += 2;
9308  }
9309  else if(ShiftKey)
9310  {
9312  }
9313  else
9314  {
9316  }
9319  {
9321  }
9322  }
9323  else
9324  {
9325  if(CtrlKey)
9326  {
9328  }
9329  else if(ShiftKey)
9330  {
9332  }
9333  else
9334  {
9336  }
9337  Display->ClearDisplay(1);
9340  {
9341  Track->PlotSmallRedGap(1);
9342  }
9343  }
9344  ScreenRightButton->Enabled = true;
9345  Screen->Cursor = TCursor(-2); // Arrow
9346  Utilities->CallLogPop(84);
9347  }
9348  catch(const Exception &e)
9349  {
9350  ErrorLog(28, e.Message);
9351  }
9352 }
9353 // ---------------------------------------------------------------------------
9354 
9355 void __fastcall TInterface::ScreenDownButtonClick(TObject *Sender)
9356 {
9357  try
9358  {
9359  // have to allow in zoomout mode
9360  TrainController->LogEvent("ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9361  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9362  Screen->Cursor = TCursor(-11); // Hourglass;
9363  ScreenDownButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9364  // BUT - it does prevent it from retaining focus - so can use the cursor keys to scroll the display without being captured by the buttons
9365  if(!Display->ZoomOutFlag)
9366  {
9367  if(CtrlKey)
9368  {
9369  Display->DisplayOffsetV += 2;
9370  }
9371  else if(ShiftKey)
9372  {
9374  }
9375  else
9376  {
9378  }
9381  {
9383  }
9384  }
9385  else
9386  {
9387  if(CtrlKey)
9388  {
9390  }
9391  else if(ShiftKey)
9392  {
9394  }
9395  else
9396  {
9398  }
9399  Display->ClearDisplay(2);
9402  {
9403  Track->PlotSmallRedGap(2);
9404  }
9405  }
9406  ScreenDownButton->Enabled = true;
9407  Screen->Cursor = TCursor(-2); // Arrow
9408  Utilities->CallLogPop(85);
9409  }
9410  catch(const Exception &e)
9411  {
9412  ErrorLog(29, e.Message);
9413  }
9414 }
9415 // ---------------------------------------------------------------------------
9416 
9417 void __fastcall TInterface::ScreenUpButtonClick(TObject *Sender)
9418 {
9419  try
9420  {
9421  // have to allow in zoomout mode
9422  TrainController->LogEvent("ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9423  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9424  Screen->Cursor = TCursor(-11); // Hourglass;
9425  ScreenUpButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9426  if(!Display->ZoomOutFlag)
9427  {
9428  if(CtrlKey)
9429  {
9430  Display->DisplayOffsetV -= 2;
9431  }
9432  else if(ShiftKey)
9433  {
9435  }
9436  else
9437  {
9439  }
9442  {
9444  }
9445  }
9446  else
9447  {
9448  if(CtrlKey)
9449  {
9451  }
9452  else if(ShiftKey)
9453  {
9455  }
9456  else
9457  {
9459  }
9460  Display->ClearDisplay(3);
9463  {
9464  Track->PlotSmallRedGap(3);
9465  }
9466  }
9467  ScreenUpButton->Enabled = true;
9468  Screen->Cursor = TCursor(-2); // Arrow
9469  Utilities->CallLogPop(86);
9470  }
9471  catch(const Exception &e)
9472  {
9473  ErrorLog(30, e.Message);
9474  }
9475 }
9476 // ---------------------------------------------------------------------------
9477 
9478 void __fastcall TInterface::ZoomButtonClick(TObject *Sender)
9479 {
9480  try
9481  {
9482  // have to allow in zoomout mode
9483  TrainController->LogEvent("ZoomButtonClick");
9484  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ZoomButtonClick");
9485  Screen->Cursor = TCursor(-11); // Hourglass;
9486  ZoomButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9487  if(Display->ZoomOutFlag) // i.e resume zoomed in view
9488  {
9489  TrainController->LogEvent("ZoomButtonClick + ZoomOutFlag");
9490 // TLevel2OperMode TempLevel2OperMode = Level2OperMode;
9491  if(Level1Mode == BaseMode)
9492  {
9493  InfoPanel->Visible = false; // reset infopanel in case not set later
9494  InfoPanel->Caption = "";
9495  SetLevel1Mode(18);
9496  }
9497  else if(Level1Mode == TrackMode)
9498  {
9499  InfoPanel->Visible = false; // reset infopanel in case not set later
9500  InfoPanel->Caption = "";
9501  // set edit menu items
9503  SetLevel2TrackMode(33); // revert to earlier track mode from zoom
9504  }
9505  else if(Level1Mode == PrefDirMode)
9506  {
9508  {
9509  SetLevel1Mode(19); // to redisplay infopanel caption "...select start..."
9510  }
9511  else
9512  {
9513  SetLevel2PrefDirMode(4); // revert to PrefDirContinuing PrefDir mode
9514  }
9515  }
9516 // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
9517 // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
9518  else if(Level1Mode == TimetableMode)
9519  {
9520  InfoPanel->Visible = false;
9521  }
9522  // Don't include OperMode or RestartSessionOperMode as they reset the performance file
9523  else if(Level2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
9524  {
9525  OperateButton->Enabled = true;
9526  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
9527  ExitOperationButton->Enabled = true;
9529  }
9530  else if(Level2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
9531  {
9532  OperateButton->Enabled = true;
9533  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
9534  ExitOperationButton->Enabled = true;
9535  TTClockAdjButton->Enabled = true;
9538  }
9539  else if(Level2OperMode == PreStart)
9540  {
9541  OperateButton->Enabled = true;
9542  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
9543  ExitOperationButton->Enabled = true;
9544  TTClockAdjButton->Enabled = true;
9546  }
9547  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
9549  ClearandRebuildRailway(43); // need to call this after ZoomOutFlag reset to display track, even if Clearand... already called
9550  // earlier during level mode setting - because until ZoomOutFlag reset PlotOutput plots nothing
9551  }
9552  else // set zoomed out view
9553  {
9554  TrainController->LogEvent("ZoomButtonClick + != ZoomOutFlag");
9555  Display->ZoomOutFlag = true;
9557  FileMenu->Enabled = false;
9558  ModeMenu->Enabled = false;
9559  EditMenu->Enabled = false;
9560  TextBox->Visible = false;
9561  LocationNameTextBox->Visible = false;
9562  TTClockAdjButton->Enabled = false;
9563 // DisablePanelsStoreMainMenuStates();//ensure Display->ZoomOutFlag set true before calling
9564  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
9565  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
9566 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
9567  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
9568  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
9569  if((LeftExcess > 0) && (RightExcess > 0))
9570  {
9571  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
9572  }
9573  else if((LeftExcess > 0) && (RightExcess <= 0))
9574  {
9575  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
9576  (Utilities->ScreenElementWidth / 2); // normalise to nearest screen
9577  }
9578  else if((LeftExcess <= 0) && (RightExcess > 0))
9579  {
9580  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
9581  }
9582  else
9583  {
9584  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
9585 
9586  }
9587  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
9588  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
9589  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
9590  if((TopExcess > 0) && (BotExcess > 0))
9591  {
9592  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
9593  }
9594  else if((TopExcess > 0) && (BotExcess <= 0))
9595  {
9596  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
9597  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
9598  }
9599  else if((TopExcess <= 0) && (BotExcess > 0))
9600  {
9601  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
9602  }
9603  else
9604  {
9605  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
9606 
9607  }
9608  Display->ClearDisplay(4);
9612  {
9613  Track->PlotSmallRedGap(4);
9614  }
9615  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomIn");
9616  }
9617  Screen->Cursor = TCursor(-2); // Arrow
9618  ZoomButton->Enabled = true; // restore, see above
9619  Utilities->CallLogPop(87);
9620  }
9621  catch(const Exception &e)
9622  {
9623  ErrorLog(31, e.Message);
9624  }
9625 }
9626 // ---------------------------------------------------------------------------
9627 
9628 void __fastcall TInterface::HomeButtonClick(TObject *Sender)
9629 {
9630  try
9631  {
9632  // have to allow in zoomout mode
9633  TrainController->LogEvent("HomeButtonClick");
9634  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HomeButtonClick");
9635  Screen->Cursor = TCursor(-11); // Hourglass;
9636  HomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9637  if(!Display->ZoomOutFlag) // zoomed in mode
9638  {
9639  TrainController->LogEvent("HomeButtonClick + zoomed in mode");
9643  {
9645  }
9646  }
9647  else
9648  {
9649  // zoomed out mode
9650  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
9651  TrainController->LogEvent("HomeButtonClick + zoomed out mode");
9653  Display->ClearDisplay(9);
9656  {
9657  Track->PlotSmallRedGap(5);
9658  }
9659  }
9660  Screen->Cursor = TCursor(-2); // Arrow
9661  HomeButton->Enabled = true; // restore, see above
9662  Utilities->CallLogPop(88);
9663  }
9664  catch(const Exception &e)
9665  {
9666  ErrorLog(32, e.Message);
9667  }
9668 }
9669 
9670 // ---------------------------------------------------------------------------
9671 void __fastcall TInterface::NewHomeButtonClick(TObject *Sender)
9672 {
9673  try
9674  {
9675  TrainController->LogEvent("NewHomeButtonClick");
9676  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewHomeButtonClick");
9677  NewHomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9678  if(!Display->ZoomOutFlag) // zoomed in mode
9679  {
9682  ResetChangedFileDataAndCaption(23, false); // false because no major changes made
9683  }
9684  else
9685  {
9688  }
9689  Utilities->CallLogPop(1188);
9690  NewHomeButton->Enabled = true; // restore, see above
9691  }
9692  catch(const Exception &e)
9693  {
9694  ErrorLog(174, e.Message);
9695  }
9696 }
9697 
9698 // ---------------------------------------------------------------------------
9699 void __fastcall TInterface::EditMenuClick(TObject *Sender)
9700 // added at v2.1.0 to allow CTRL+X, CTRL+C & CTRL+V in edit menu (see case BaseMode for more information)
9701 {
9702  try
9703  {
9704  CopyMenuItem->ShortCut = TextToShortCut("Ctrl+C");
9705  CutMenuItem->ShortCut = TextToShortCut("Ctrl+X");
9706  PasteMenuItem->ShortCut = TextToShortCut("Ctrl+V");
9707  }
9708  catch(const Exception &e)
9709  {
9710  ErrorLog(196, e.Message);
9711  }
9712 }
9713 
9714 // ---------------------------------------------------------------------------
9715 void __fastcall TInterface::SelectMenuItemClick(TObject *Sender)
9716 {
9717 // draw a rectangle with the left mouse button, enclosing whole 16 x 16 squares
9718  try
9719  {
9720  TrainController->LogEvent("SelectMenuItemClick");
9721  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectMenuItemClick");
9722  if(Level1Mode == TrackMode)
9723  {
9724  SelectionValid = false;
9726  SetLevel2TrackMode(34);
9728  {
9729  ShowMessage("Please be aware when pasting that anything inside the pasted area will be overwritten.\n\nThis warning will not be shown again.");
9730  PasteWarningSentFlag = true;
9731  }
9732  }
9733  else if(Level1Mode == PrefDirMode)
9734  {
9737  }
9738  Utilities->CallLogPop(1189);
9739  }
9740  catch(const Exception &e)
9741  {
9742  ErrorLog(145, e.Message);
9743  }
9744 }
9745 
9746 // ---------------------------------------------------------------------------
9747 void __fastcall TInterface::ReselectMenuItemClick(TObject *Sender)
9748 {
9749  try
9750  {
9751  TrainController->LogEvent("ReselectMenuItemClick");
9752  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectMenuItemClick");
9753  if((SelectBitmap->Height == 0) || (SelectBitmap->Width == 0))
9754  {
9755  Utilities->CallLogPop(1424);
9756  return;
9757  }
9758  int TLHCH = SelectBitmapHLoc;
9759  int TLHCV = SelectBitmapVLoc;
9760  int BRHCH = TLHCH + (SelectBitmap->Width / 16);
9761  int BRHCV = TLHCV + (SelectBitmap->Height / 16);
9762  TRect NewSelectRect(TLHCH, TLHCV, BRHCH, BRHCV);
9763  SelectRect = NewSelectRect;
9765  // set bitmap to reselected area (may be different if flip or mirror had been selected earlier)
9766  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
9767  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
9768  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
9769  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
9770 
9771  SelectionValid = true;
9772  ReselectMenuItem->Enabled = false;
9773  CutMenuItem->Enabled = true;
9774  CopyMenuItem->Enabled = true;
9775  FlipMenuItem->Enabled = true;
9776  MirrorMenuItem->Enabled = true;
9777  RotRightMenuItem->Enabled = true;
9778  RotLeftMenuItem->Enabled = true;
9779  RotateMenuItem->Enabled = true;
9780  PasteMenuItem->Enabled = false;
9781  DeleteMenuItem->Enabled = true;
9782  if(Track->IsTrackFinished())
9783  {
9784  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
9785  }
9786  else
9787  {
9788  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
9789  }
9790  SelectBiDirPrefDirsMenuItem->Visible = false;
9791  CheckPrefDirConflictsMenuItem->Visible = false;
9792  CancelSelectionMenuItem->Enabled = true;
9793  mbLeftDown = false;
9794  // Level1Mode = TrackMode;
9795  // SetLevel1Mode(68);
9797  SetLevel2TrackMode(47);
9798  Utilities->CallLogPop(1425);
9799  }
9800  catch(const Exception &e)
9801  {
9802  ErrorLog(146, e.Message);
9803  }
9804 }
9805 
9806 // ---------------------------------------------------------------------------
9807 void __fastcall TInterface::CutMenuItemClick(TObject *Sender)
9808 {
9809  try
9810  {
9811  TrainController->LogEvent("CutMenuItemClick");
9812  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutMenuItemClick");
9813  // Level1Mode = TrackMode;
9814  // SetLevel1Mode(69);
9815  CopySelected = false; // new at v2.8.0
9816  LoadClipboard(0); // new at v2.8.0
9818  SetLevel2TrackMode(35);
9819  Utilities->CallLogPop(1190);
9820  }
9821  catch(const Exception &e)
9822  {
9823  ErrorLog(147, e.Message);
9824  }
9825 }
9826 // ---------------------------------------------------------------------------
9827 
9828 void __fastcall TInterface::CopyMenuItemClick(TObject *Sender)
9829 {
9830  try
9831  {
9832  TrainController->LogEvent("CopyMenuItemClick");
9833  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyMenuItemClick");
9834  // Level1Mode = TrackMode;
9835  // SetLevel1Mode(70);
9836  CopySelected = true; // new at v2.8.0
9837  LoadClipboard(1); // new at v2.8.0
9839  SetLevel2TrackMode(36);
9840  Utilities->CallLogPop(1191);
9841  }
9842  catch(const Exception &e)
9843  {
9844  ErrorLog(148, e.Message);
9845  }
9846 }
9847 
9848 // ---------------------------------------------------------------------------
9849 void __fastcall TInterface::FlipMenuItemClick(TObject *Sender)
9850 {
9851  try
9852  {
9853  TrainController->LogEvent("FlipMenuItemClick");
9854  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FlipMenuItemClick");
9855  // reset values in SelectVector
9856  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9857  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9858  {
9859  // Note: (changed again in v2.4.0 to keep attributes) need to change flip, mirror & 180deg functions as only change speedtag without changing anything else.
9860  // This didn't matter before new paste with attributes added at v2.2.0 as a new element was built from the speedtag,
9861  // but now if do a reselect then cut and paste with attributes the wrong graphic is pasted and all other attributes
9862  // are wrong. Need to rebuild a new TrackElement from the new speedtag and use that in the select vector.
9863  // Note that if use Flip, mirror etc then all attributes lost anyway so ok to build a basic element.
9864  int VLoc = VerSum - Track->SelectVectorAt(8, x).VLoc;
9865  int HLoc = Track->SelectVectorAt(7, x).HLoc;
9867  TE.VLoc = VLoc;
9868  TE.HLoc = HLoc;
9869 
9870  TE.ActiveTrackElementName = Track->SelectVectorAt(37, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9872  TE.Length01 = Track->SelectVectorAt(39, x).Length01;
9873  TE.Length23 = Track->SelectVectorAt(40, x).Length23;
9876  TE.SigAspect = Track->SelectVectorAt(43, x).SigAspect;
9877  Track->SelectVectorAt(26, x) = TE;
9878  }
9879 
9880  int FlipLinkArray[10] =
9881  {
9882  0, 7, 8, 9, 4, 5, 6, 1, 2, 3
9883  }; //0 & 5 are never used
9884 
9885  TrainController->LogEvent("Flip-track ok");
9886  // now reset the pref dirs
9887  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
9888  {
9889  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
9890  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9891  int VLoc = VerSum - SelectPrefDir->PrefDirVector.at(x).VLoc;
9892  int HLoc = SelectPrefDir->PrefDirVector.at(x).HLoc;
9893  int ELink = FlipLinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
9894  int XLink = FlipLinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
9896  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
9897  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
9898  TPrefDirElement PDE(TE); //this has Link[4]
9899  PDE.HLoc = HLoc;
9900  PDE.VLoc = VLoc;
9901  PDE.SetELink(ELink);
9902  PDE.SetXLink(XLink);
9903  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
9904  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
9905  {
9906  if(!ELinkPosFound && (PDE.Link[y] == ELink))
9907  {
9908  PDE.SetELinkPos(y);
9909  ELinkPosFound = true;
9910  }
9911  if(!XLinkPosFound && (PDE.Link[y] == XLink))
9912  {
9913  PDE.SetXLinkPos(y);
9914  XLinkPosFound = true;
9915  }
9916  }
9917  //set the CheckCount as before - added at v2.9.1
9918  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
9921 
9922  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
9923  bool FoundFlag = false;
9924  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(61, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
9925  if(PDE.GetSignedIntTrackVectorPosition() < 0)
9926  {
9927  FoundFlag = false; //probably will be anyway but reset to be sure & test below
9928  }
9930  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
9931  {
9933  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
9934  break;
9935  }
9936  SelectPrefDir->PrefDirVector.at(x) = PDE;
9937  }
9938 
9939  TrainController->LogEvent("Flip-prefdirs ok");
9940  // reset values in SelectTextVector
9941  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(0); x++)
9942  {
9944  // also subtract font height, brings position approximately right
9945  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
9946  }
9947  TrainController->LogEvent("Flip-text ok");
9948  // reset values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
9949  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9950  {
9951  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
9952  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
9953  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
9954  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
9955  }
9957  SetLevel2TrackMode(48);
9958  Utilities->CallLogPop(1426);
9959  }
9960  catch(const Exception &e)
9961  {
9962  ErrorLog(149, e.Message);
9963  }
9964 }
9965 
9966 // ---------------------------------------------------------------------------
9967 void __fastcall TInterface::MirrorMenuItemClick(TObject *Sender)
9968 {
9969  try
9970  {
9971  TrainController->LogEvent("MirrorMenuItemClick");
9972  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MirrorMenuItemClick");
9973  // reset values in SelectVector
9974  int HorSum = SelectRect.left + SelectRect.right - 1;
9975  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9976  {
9977  // See note above for FlipMenuItem relating to mods for v2.2.0
9978  int VLoc = Track->SelectVectorAt(22, x).VLoc;
9979  int HLoc = HorSum - Track->SelectVectorAt(6, x).HLoc;
9981  TE.VLoc = VLoc;
9982  TE.HLoc = HLoc;
9983 
9984  TE.ActiveTrackElementName = Track->SelectVectorAt(44, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9986  TE.Length01 = Track->SelectVectorAt(46, x).Length01;
9987  TE.Length23 = Track->SelectVectorAt(47, x).Length23;
9990  TE.SigAspect = Track->SelectVectorAt(50, x).SigAspect;
9991 
9992 // if(Track->SelectVectorAt(28, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(29, x).SigAspect;//TrackType will be the same
9993  Track->SelectVectorAt(30, x) = TE;
9994 // Track->SelectVectorAt(, x).HLoc = HorSum - Track->SelectVectorAt(, x).HLoc;
9995 // Track->SelectVectorAt(, x).SpeedTag = Track->MirrorArray[Track->SelectVectorAt(, x).SpeedTag];
9996  }
9997 
9998  int MirrorLinkArray[10] =
9999  {
10000  0, 3, 2, 1, 6, 5, 4, 9, 8, 7
10001  }; //0 & 5 are never used
10002 
10003  TrainController->LogEvent("Mirror-track ok");
10004  // now reset the pref dirs
10005  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
10006  {
10007  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
10008  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
10009  int HLoc = HorSum - SelectPrefDir->PrefDirVector.at(x).HLoc;
10010  int VLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
10011  int ELink = MirrorLinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
10012  int XLink = MirrorLinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
10014  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
10015  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
10016  TPrefDirElement PDE(TE); //this has Link[4]
10017  PDE.HLoc = HLoc;
10018  PDE.VLoc = VLoc;
10019  PDE.SetELink(ELink);
10020  PDE.SetXLink(XLink);
10021  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
10022  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
10023  {
10024  if(!ELinkPosFound && (PDE.Link[y] == ELink))
10025  {
10026  PDE.SetELinkPos(y);
10027  ELinkPosFound = true;
10028  }
10029  if(!XLinkPosFound && (PDE.Link[y] == XLink))
10030  {
10031  PDE.SetXLinkPos(y);
10032  XLinkPosFound = true;
10033  }
10034  }
10035  //set the CheckCount as before - added at v2.9.1
10036  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10039  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10040  bool FoundFlag = false;
10041  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(62, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10042  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10043  {
10044  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10045  }
10047  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10048  {
10050  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10051  break;
10052  }
10053  SelectPrefDir->PrefDirVector.at(x) = PDE;
10054  }
10055 
10056  TrainController->LogEvent("Mirror-PDs ok");
10057  // reset values in SelectTextVector
10058  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(1); x++)
10059  {
10061  // also subtract half font height for each letter of text, brings position approximately right
10062  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
10063  }
10064  TrainController->LogEvent("Mirror-text ok");
10065  // reset values in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
10066  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10067  {
10068  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
10069  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
10070  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
10071  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
10072  {
10073  LeftPosAfterMirror = SelectRect.left * 16;
10074  }
10075  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
10076  }
10078  SetLevel2TrackMode(49);
10079  Utilities->CallLogPop(1427);
10080  }
10081  catch(const Exception &e)
10082  {
10083  ErrorLog(150, e.Message);
10084  }
10085 }
10086 
10087 // ---------------------------------------------------------------------------
10088 void __fastcall TInterface::RotateMenuItemClick(TObject *Sender)
10089 {
10090  try
10091  {
10092  TrainController->LogEvent("Rotate180MenuItemClick");
10093  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",Rotate180MenuItemClick");
10094 
10095  // reset values in SelectVector
10096  int HorSum = SelectRect.left + SelectRect.right - 1;
10097  int VerSum = SelectRect.top + SelectRect.bottom - 1;
10098  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10099  {
10100  // See note above for FlipMenuItem relating to mods for v2.2.0
10101  int VLoc = VerSum - Track->SelectVectorAt(23, x).VLoc;
10102  int HLoc = HorSum - Track->SelectVectorAt(36, x).HLoc;
10104  TE.VLoc = VLoc;
10105  TE.HLoc = HLoc;
10106 
10107  TE.ActiveTrackElementName = Track->SelectVectorAt(51, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
10109  TE.Length01 = Track->SelectVectorAt(53, x).Length01;
10110  TE.Length23 = Track->SelectVectorAt(54, x).Length23;
10113  TE.SigAspect = Track->SelectVectorAt(57, x).SigAspect;
10114 
10115 // if(Track->SelectVectorAt(32, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(33, x).SigAspect; dropped in v2.4.0 for above
10116  Track->SelectVectorAt(34, x) = TE;
10117 // TTrackElement &TempEl = Track->SelectVectorAt(13, x);
10118 // TempEl.HLoc = HorSum - TempEl.HLoc;
10119 // TempEl.VLoc = VerSum - TempEl.VLoc;
10120 // TempEl.SpeedTag = Track->MirrorArray[Track->FlipArray[TempEl.SpeedTag]];
10121  }
10122 
10123  int Rot180LinkArray[10] =
10124  {
10125  0, 9, 8, 7, 6, 5, 4, 3, 2, 1
10126  }; //0 & 5 are never used
10127  TrainController->LogEvent("Rotate-track ok");
10128  // now reset the pref dirs
10129  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
10130  {
10131  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
10132  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
10133  int HLoc = HorSum - SelectPrefDir->PrefDirVector.at(x).HLoc;
10134  int VLoc = VerSum - SelectPrefDir->PrefDirVector.at(x).VLoc;
10135  int ELink = Rot180LinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
10136  int XLink = Rot180LinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
10138  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
10139  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
10140  TPrefDirElement PDE(TE); //this has Link[4]
10141  PDE.HLoc = HLoc;
10142  PDE.VLoc = VLoc;
10143  PDE.SetELink(ELink);
10144  PDE.SetXLink(XLink);
10145  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
10146  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
10147  {
10148  if(!ELinkPosFound && (PDE.Link[y] == ELink))
10149  {
10150  PDE.SetELinkPos(y);
10151  ELinkPosFound = true;
10152  }
10153  if(!XLinkPosFound && (PDE.Link[y] == XLink))
10154  {
10155  PDE.SetXLinkPos(y);
10156  XLinkPosFound = true;
10157  }
10158  }
10159  //set the CheckCount as before - added at v2.9.1
10160  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10163  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10164  bool FoundFlag = false;
10165  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(63, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10166  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10167  {
10168  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10169  }
10171  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10172  {
10174  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10175  break;
10176  }
10177  SelectPrefDir->PrefDirVector.at(x) = PDE;
10178  }
10179  TrainController->LogEvent("Rotate-PDs ok");
10180  // reset values in SelectTextVector
10181  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(2); x++)
10182  {
10184  // also subtract half font height for each letter of text, brings position approximately right horizontally
10185  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
10186  // also subtract font height, brings position approximately right vertically
10187  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
10188  }
10189  TrainController->LogEvent("Rotate-text ok");
10190  // reset flip values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
10191  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10192  {
10193  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
10194  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
10195  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
10196  if(TopPosAfterFlip < (SelectRect.top * 16)) // shouldn't go above top but check
10197  {
10198  TopPosAfterFlip = SelectRect.top * 16;
10199  }
10200  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
10201  }
10202  // reset mirror in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
10203  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10204  {
10205  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
10206  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
10207  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
10208  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
10209  {
10210  LeftPosAfterMirror = SelectRect.left * 16;
10211  }
10212  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
10213  }
10214  // Level1Mode = TrackMode;
10215  // SetLevel1Mode(73);
10217  SetLevel2TrackMode(50);
10218  Utilities->CallLogPop(1435);
10219  }
10220  catch(const Exception &e)
10221  {
10222  ErrorLog(151, e.Message);
10223  }
10224 }
10225 // ---------------------------------------------------------------------------
10226 
10227 void __fastcall TInterface::RotRightMenuItemClick(TObject *Sender)
10228 {
10229  try
10230  {
10231  TrainController->LogEvent("RotateRightMenuItemClick");
10232  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateRightMenuItemClick");
10233  Screen->Cursor = TCursor(-11); // Hourglass
10234  // check first if a square and if not give message & quit
10235  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
10236  {
10237  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
10238  int VertSize = SelectRect.bottom - SelectRect.top;
10239  if((SelectRect.left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
10240  {
10241  // use right hand vertical & make square to left of that
10242  SelectRect.left = SelectRect.right - VertSize;
10243  }
10244  else
10245  {
10246  SelectRect.right = SelectRect.left + VertSize;
10247  }
10250  int button = Application->MessageBox
10251  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
10252  L"Left click and hold here to move this message box", MB_OKCANCEL);
10253  if(button == IDCANCEL)
10254  {
10255  ResetSelectRect();
10256  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
10257  SetLevel1Mode(133);
10259  SetLevel2TrackMode(59);
10261  Screen->Cursor = TCursor(-2); // Arrow
10262  Utilities->CallLogPop(2121);
10263  return;
10264  }
10265  }
10266  // set SelectBitmap (only need the dimensions here as not moving the selection)
10269  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
10270  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
10271 
10272  // store track elements and text in select vectors - have to store here because original selection might well have changed
10274  TTrackElement TempElement; // default element
10275  bool FoundFlag;
10276  for(int x = SelectRect.left; x < SelectRect.right; x++)
10277  {
10278  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10279  {
10280  int ATVecPos = Track->GetVectorPositionFromTrackMap(57, x, y, FoundFlag);
10281  if(FoundFlag)
10282  {
10283  TempElement = Track->TrackElementAt(959, ATVecPos);
10284  if(TempElement.SpeedTag > 0)
10285  {
10286  Track->SelectPush(TempElement);
10287  }
10288  }
10289  }
10290  }
10291  // now store inactive elements
10292  for(int x = SelectRect.left; x < SelectRect.right; x++)
10293  {
10294  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10295  {
10296  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(28, x, y, FoundFlag);
10297  if(FoundFlag)
10298  {
10299  TempElement = Track->InactiveTrackElementAt(126, IATVecPair.first);
10300  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
10301  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
10302  {
10303  TempElement = Track->InactiveTrackElementAt(127, IATVecPair.second);
10304  Track->SelectPush(TempElement);
10305  }
10306  }
10307  }
10308  }
10309  TrainController->LogEvent("RotRight-trackstore ok");
10310  //store preferred directions //added at v2.9.0
10311  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
10312  TPrefDirElement TempPrefDirElement;
10314  for(int x = SelectRect.left; x < SelectRect.right; x++)
10315  {
10316  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10317  {
10318  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(12, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
10319  if(FoundFlag)
10320  {
10321  if(PrefDirPos0 > -1)
10322  {
10323  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(6, PrefDirPos0);
10324  SelectPrefDir->ExternalStorePrefDirElement(12, TempPrefDirElement);
10325  }
10326  if(PrefDirPos1 > -1)
10327  {
10328  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(7, PrefDirPos1);
10329  SelectPrefDir->ExternalStorePrefDirElement(13, TempPrefDirElement);
10330  }
10331  if(PrefDirPos2 > -1)
10332  {
10333  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(8, PrefDirPos2);
10334  SelectPrefDir->ExternalStorePrefDirElement(14, TempPrefDirElement);
10335  }
10336  if(PrefDirPos3 > -1)
10337  {
10338  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(9, PrefDirPos3);
10339  SelectPrefDir->ExternalStorePrefDirElement(15, TempPrefDirElement);
10340  }
10341  }
10342  }
10343  }
10344  TrainController->LogEvent("RotRight-PDstore ok");
10345  // store text items
10346  int LowSelectHPos = SelectRect.left * 16;
10347  int HighSelectHPos = SelectRect.right * 16;
10348  int LowSelectVPos = SelectRect.top * 16;
10349  int HighSelectVPos = SelectRect.bottom * 16;
10350  TextHandler->SelectTextVector.clear();
10351  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
10352  {
10353  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
10354  {
10355  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
10356  {
10357  // have to create a new TextItem in order to create a new Font object
10358  // BUT: only create new items where they don't appear as named location names
10359  // in SelectVector, since those names shouldn't be copied or pasted.
10360  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
10361  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
10362  bool SelectVectorNamedElement = false;
10363  AnsiString SelectTextString; // new at v2.2.0
10364  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
10365  {
10366  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
10367  {
10368  SelectVectorNamedElement = true;
10369  break;
10370  }
10371  }
10372  if(SelectVectorNamedElement) // changed at v2.2.0
10373  {
10374  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
10375  }
10376  else // new at v2.2.0
10377  {
10378  SelectTextString = TextPtr->TextString;
10379  }
10380  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
10381  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
10382  }
10383  }
10384  }
10385  TrainController->LogEvent("RotRight-textstore ok");
10386  // store graphic items, but first clear SelectGraphicVector
10387  Track->SelectGraphicVector.clear();
10388  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
10389  {
10390  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
10391  UserGraphicPtr++)
10392  {
10393  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
10394  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
10395  {
10396  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
10397  }
10398  }
10399  }
10400  TrainController->LogEvent("RotRight-graphicstore ok");
10401  // now transform the H & V for rh rotate
10402  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10403  {
10404  int HLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(74, x).VLoc;
10405  int VLoc = SelectRect.top - SelectRect.left + Track->SelectVectorAt(75, x).HLoc;
10407  TE.VLoc = VLoc;
10408  TE.HLoc = HLoc;
10409 
10410  TE.ActiveTrackElementName = Track->SelectVectorAt(58, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
10412  TE.Length01 = Track->SelectVectorAt(60, x).Length01;
10413  TE.Length23 = Track->SelectVectorAt(61, x).Length23;
10416  TE.SigAspect = Track->SelectVectorAt(64, x).SigAspect;
10417  Track->SelectVectorAt(65, x) = TE;
10418  }
10419 
10420  int RotRightLinkArray[10] =
10421  {
10422  0, 3, 6, 9, 2, 5, 8, 1, 4, 7
10423  }; //0 & 5 are never used
10424  TrainController->LogEvent("RotRight-trackrotate ok");
10425  // now transform the pref dirs
10426  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
10427  {
10428  int OriginalHLoc = SelectPrefDir->GetFixedPrefDirElementAt(250, x).HLoc; //added at v2.9.1
10429  int OriginalVLoc = SelectPrefDir->GetFixedPrefDirElementAt(251, x).VLoc;
10430  int HLoc = SelectRect.bottom - 1 + SelectRect.left - OriginalVLoc;
10431  int VLoc = SelectRect.top - SelectRect.left + OriginalHLoc;
10432  int ELink = RotRightLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(252, x).GetELink()];
10433  int XLink = RotRightLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(253, x).GetXLink()];
10435  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
10436  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
10437  TPrefDirElement PDE(TE); //this has Link[4]
10438  PDE.HLoc = HLoc;
10439  PDE.VLoc = VLoc;
10440  PDE.SetELink(ELink);
10441  PDE.SetXLink(XLink);
10442  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
10443  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
10444  {
10445  if(!ELinkPosFound && (PDE.Link[y] == ELink))
10446  {
10447  PDE.SetELinkPos(y);
10448  ELinkPosFound = true;
10449  }
10450  if(!XLinkPosFound && (PDE.Link[y] == XLink))
10451  {
10452  PDE.SetXLinkPos(y);
10453  XLinkPosFound = true;
10454  }
10455  }
10456  //set the CheckCount as before - added at v2.9.1
10457  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10460  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10461  bool FoundFlag = false;
10462  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(64, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10463  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10464  {
10465  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10466  }
10468  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10469  {
10471  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10472  break;
10473  }
10474  SelectPrefDir->PrefDirVector.at(x) = PDE;
10475  }
10476  TrainController->LogEvent("RotRight-PDrotate ok");
10477  // reset values in SelectTextVector
10478  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(3); x++)
10479  {
10480 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
10481 // & if a lot then some will extend beyond the selection
10483  // also subtract half font height for each letter of text, brings position approximately right horizontally
10484  TextItem->HPos = (SelectRect.left) * 16;
10485  TextItem->VPos = (SelectRect.top + x) * 16;
10486  }
10487  TrainController->LogEvent("RotRight-textrotate ok");
10488  // reset values in SelectGraphicVector
10489  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10490  {
10491  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
10492  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
10493  int MidHPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidVPosBeforeRotate;
10494  int MidVPosAfterRotate = ((SelectRect.top - SelectRect.left) * 16) + MidHPosBeforeRotate;
10495  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
10496  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
10497  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
10498  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
10499  }
10500  Screen->Cursor = TCursor(-2); // Arrow
10502  SetLevel2TrackMode(60);
10503  Utilities->CallLogPop(2122);
10504  }
10505  catch(const Exception &e)
10506  {
10507  ErrorLog(205, e.Message);
10508  }
10509 }
10510 
10511 // ---------------------------------------------------------------------------
10512 
10513 void __fastcall TInterface::RotLeftMenuItemClick(TObject *Sender)
10514 {
10515  try
10516  {
10517  TrainController->LogEvent("RotateLeftMenuItemClick");
10518  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateLeftMenuItemClick");
10519  Screen->Cursor = TCursor(-11); // Hourglass;
10520  // check first if a square and if not give message & quit
10521  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
10522  {
10523  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
10524  int VertSize = SelectRect.bottom - SelectRect.top;
10525  if((SelectRect.left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
10526  {
10527  // use right hand vertical & make square to left of that
10528  SelectRect.left = SelectRect.right - VertSize;
10529  }
10530  else
10531  {
10532  SelectRect.right = SelectRect.left + VertSize;
10533  }
10536  int button = Application->MessageBox
10537  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
10538  L"Left click and hold here to move this message box", MB_OKCANCEL);
10539  if(button == IDCANCEL)
10540  {
10541  ResetSelectRect();
10542  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
10543  SetLevel1Mode(134);
10545  SetLevel2TrackMode(61);
10547  Screen->Cursor = TCursor(-2); // Arrow
10548  Utilities->CallLogPop(2123);
10549  return;
10550  }
10551  }
10552  // set SelectBitmap (only need the dimensions here as not moving the selection)
10555  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
10556  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
10557 
10558  // store track elements and text in select vectors - have to store here because original selection might well have changed
10560  TTrackElement TempElement; // default element
10561  bool FoundFlag;
10562  for(int x = SelectRect.left; x < SelectRect.right; x++)
10563  {
10564  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10565  {
10566  int ATVecPos = Track->GetVectorPositionFromTrackMap(58, x, y, FoundFlag);
10567  if(FoundFlag)
10568  {
10569  TempElement = Track->TrackElementAt(960, ATVecPos);
10570  if(TempElement.SpeedTag > 0)
10571  {
10572  Track->SelectPush(TempElement);
10573  }
10574  }
10575  }
10576  }
10577  // now store inactive elements
10578  for(int x = SelectRect.left; x < SelectRect.right; x++)
10579  {
10580  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10581  {
10582  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(29, x, y, FoundFlag);
10583  if(FoundFlag)
10584  {
10585  TempElement = Track->InactiveTrackElementAt(128, IATVecPair.first);
10586  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
10587  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
10588  {
10589  TempElement = Track->InactiveTrackElementAt(129, IATVecPair.second);
10590  Track->SelectPush(TempElement);
10591  }
10592  }
10593  }
10594  }
10595  TrainController->LogEvent("RotLeft-trackstore ok");
10596  //store preferred directions //added at v2.9.0
10597  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
10598  TPrefDirElement TempPrefDirElement;
10600  for(int x = SelectRect.left; x < SelectRect.right; x++)
10601  {
10602  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10603  {
10604  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(13, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
10605  if(FoundFlag)
10606  {
10607  if(PrefDirPos0 > -1)
10608  {
10609  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(10, PrefDirPos0);
10610  SelectPrefDir->ExternalStorePrefDirElement(16, TempPrefDirElement);
10611  }
10612  if(PrefDirPos1 > -1)
10613  {
10614  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(11, PrefDirPos1);
10615  SelectPrefDir->ExternalStorePrefDirElement(17, TempPrefDirElement);
10616  }
10617  if(PrefDirPos2 > -1)
10618  {
10619  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(12, PrefDirPos2);
10620  SelectPrefDir->ExternalStorePrefDirElement(18, TempPrefDirElement);
10621  }
10622  if(PrefDirPos3 > -1)
10623  {
10624  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(13, PrefDirPos3);
10625  SelectPrefDir->ExternalStorePrefDirElement(19, TempPrefDirElement);
10626  }
10627  }
10628  }
10629  }
10630  TrainController->LogEvent("RotLeft-PDstore ok");
10631  // store text items
10632  int LowSelectHPos = SelectRect.left * 16;
10633  int HighSelectHPos = SelectRect.right * 16;
10634  int LowSelectVPos = SelectRect.top * 16;
10635  int HighSelectVPos = SelectRect.bottom * 16;
10636  TextHandler->SelectTextVector.clear();
10637  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
10638  {
10639  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
10640  {
10641  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
10642  {
10643  // have to create a new TextItem in order to create a new Font object
10644  // BUT: only create new items where they don't appear as named location names
10645  // in SelectVector, since those names shouldn't be copied or pasted.
10646  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
10647  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
10648  bool SelectVectorNamedElement = false;
10649  AnsiString SelectTextString; // new at v2.2.0
10650  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
10651  {
10652  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
10653  {
10654  SelectVectorNamedElement = true;
10655  break;
10656  }
10657  }
10658  if(SelectVectorNamedElement) // changed at v2.2.0
10659  {
10660  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
10661  }
10662  else // new at v2.2.0
10663  {
10664  SelectTextString = TextPtr->TextString;
10665  }
10666  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
10667  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
10668  }
10669  }
10670  }
10671  TrainController->LogEvent("RotLeft-textstore ok");
10672  // store graphic items, but first clear SelectGraphicVector
10673  Track->SelectGraphicVector.clear();
10674  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
10675  {
10676  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
10677  UserGraphicPtr++)
10678  {
10679  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
10680  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
10681  {
10682  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
10683  }
10684  }
10685  }
10686  TrainController->LogEvent("RotLeft-graphicstore ok");
10687  // now transform the H & V for lh rotate
10688  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10689  {
10690  int HLoc = SelectRect.left - SelectRect.top + Track->SelectVectorAt(76, x).VLoc;
10691  int VLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(77, x).HLoc;
10693  TE.VLoc = VLoc;
10694  TE.HLoc = HLoc;
10695 
10696  TE.ActiveTrackElementName = Track->SelectVectorAt(66, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
10698  TE.Length01 = Track->SelectVectorAt(68, x).Length01;
10699  TE.Length23 = Track->SelectVectorAt(69, x).Length23;
10702  TE.SigAspect = Track->SelectVectorAt(72, x).SigAspect;
10703  Track->SelectVectorAt(73, x) = TE;
10704  }
10705 
10706  int RotLeftLinkArray[10] =
10707  {
10708  0, 7, 4, 1, 8, 5, 2, 9, 6, 3
10709  }; //0 & 5 are never used
10710  TrainController->LogEvent("RotLeft-trackrotate ok");
10711  // now transform the pref dirs
10712  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
10713  {
10714  int OriginalHLoc = SelectPrefDir->GetFixedPrefDirElementAt(255, x).HLoc; //added at v2.9.1
10715  int OriginalVLoc = SelectPrefDir->GetFixedPrefDirElementAt(256, x).VLoc;
10716  int HLoc = SelectRect.left - SelectRect.top + OriginalVLoc;
10717  int VLoc = SelectRect.bottom - 1 + SelectRect.left - OriginalHLoc;
10718  int ELink = RotLeftLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(257, x).GetELink()];
10719  int XLink = RotLeftLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(258, x).GetXLink()];
10721  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
10722  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
10723  TPrefDirElement PDE(TE); //this has Link[4] set
10724  PDE.HLoc = HLoc;
10725  PDE.VLoc = VLoc;
10726  PDE.SetELink(ELink);
10727  PDE.SetXLink(XLink);
10728  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
10729  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
10730  {
10731  if(!ELinkPosFound && (PDE.Link[y] == ELink))
10732  {
10733  PDE.SetELinkPos(y);
10734  ELinkPosFound = true;
10735  }
10736  if(!XLinkPosFound && (PDE.Link[y] == XLink))
10737  {
10738  PDE.SetXLinkPos(y);
10739  XLinkPosFound = true;
10740  }
10741  }
10742  //set the CheckCount as before - added at v2.9.1
10743  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10746  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10747  bool FoundFlag = false;
10748  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(65, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10749  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10750  {
10751  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10752  }
10754  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10755  {
10757  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10758  break;
10759  }
10760  SelectPrefDir->PrefDirVector.at(x) = PDE;
10761  }
10762  TrainController->LogEvent("RotLeft-PDrotate ok");
10763  // reset values in SelectTextVector
10764  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(4); x++)
10765  {
10766 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
10767 // & if a lot then some will extend beyond the selection
10769  // also subtract half font height for each letter of text, brings position approximately right horizontally
10770  TextItem->HPos = (SelectRect.left) * 16;
10771  TextItem->VPos = (SelectRect.top + x) * 16;
10772  }
10773  TrainController->LogEvent("RotLeft-textrotate ok");
10774  // reset values in SelectGraphicVector
10775  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10776  {
10777  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
10778  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
10779  int MidHPosAfterRotate = ((SelectRect.left - SelectRect.top) * 16) + MidVPosBeforeRotate;
10780  int MidVPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidHPosBeforeRotate;
10781  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
10782  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
10783  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
10784  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
10785  }
10786  Screen->Cursor = TCursor(-2); // Arrow
10788  SetLevel2TrackMode(62);
10789  Utilities->CallLogPop(2124);
10790  }
10791  catch(const Exception &e)
10792  {
10793  ErrorLog(206, e.Message);
10794  }
10795 }
10796 
10797 // ---------------------------------------------------------------------------
10798 
10799 void __fastcall TInterface::PasteMenuItemClick(TObject *Sender)
10800 {
10801  try
10802  {
10803  TrainController->LogEvent("PasteMenuItemClick");
10804  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteMenuItemClick");
10805  // Level1Mode = TrackMode;
10806  // SetLevel1Mode(74);
10808  SetLevel2TrackMode(58);
10809  Utilities->CallLogPop(2060);
10810  }
10811  catch(const Exception &e)
10812  {
10813  ErrorLog(198, e.Message);
10814  }
10815 }
10816 
10817 // ---------------------------------------------------------------------------
10818 void __fastcall TInterface::DeleteMenuItemClick(TObject *Sender)
10819 {
10820  try
10821  {
10822  TrainController->LogEvent("DeleteMenuItemClick");
10823  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteMenuItemClick");
10824  // Level1Mode = TrackMode;
10825  // SetLevel1Mode(75);
10827  SetLevel2TrackMode(38);
10828  Utilities->CallLogPop(1193);
10829  }
10830  catch(const Exception &e)
10831  {
10832  ErrorLog(153, e.Message);
10833  }
10834 }
10835 // ---------------------------------------------------------------------------
10836 
10837 void __fastcall TInterface::SelectLengthsMenuItemClick(TObject *Sender)
10838 {
10839  try
10840  {
10841  TrainController->LogEvent("SelectLengthsMenuItemClick");
10842  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectLengthsMenuItemClick");
10843  TrackElementPanel->Visible = false;
10844  TrackLengthPanel->Visible = true;
10845  TrackLengthPanel->SetFocus();
10846  SelectLengthsFlag = true;
10847  InfoPanel->Visible = true;
10848  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values or leave blank for no change";
10850  {
10851  ShowMessage("Note: length value will apply to each element's track within the selection.\n\nThis message will not be shown again.");
10852  LengthWarningSentFlag = true;
10853  }
10854  DistanceBox->Text = "";
10855  SpeedLimitBox->Text = "";
10858 // ResetChangedFileDataAndCaption(, true); //don't need this here after 2.7.0 as included in TrackLengthPanel buttons
10859  Utilities->CallLogPop(1414);
10860  }
10861  catch(const Exception &e)
10862  {
10863  ErrorLog(154, e.Message);
10864  }
10865 }
10866 
10867 // ---------------------------------------------------------------------------
10868 
10869 void __fastcall TInterface::SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
10870 {
10871 /* SelectVector contains all the track elements (and inactive elements but don't need them), so create up to 4 PrefDir
10872  elements from each one, and add each into ConstructPrefDir, then when all added use ConsolidatePrefDirs to add to EveryPrefDir
10873 */
10874  try
10875  {
10876  TrainController->LogEvent("SelectBiDirPrefDirsMenuItemClick");
10877  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectBiDirPrefDirsMenuItemClick");
10879  bool FoundFlag = false;
10880  if(Track->SelectVector.empty())
10881  {
10882  Utilities->CallLogPop(1550);
10883  return;
10884  }
10885  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10886  {
10887  TTrackElement TE = Track->SelectVectorAt(14, x);
10888  int VecPos = Track->GetVectorPositionFromTrackMap(42, TE.HLoc, TE.VLoc, FoundFlag);
10889  if(FoundFlag)
10890  {
10891  if((TE.TrackType == Points) || (TE.TrackType == Bridge) || (TE.TrackType == Crossover)) // 2-track element
10892  {
10893  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
10895  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
10897  TPrefDirElement PE2(TE, TE.Link[2], 2, TE.Link[3], 3, VecPos);
10899  TPrefDirElement PE3(TE, TE.Link[3], 3, TE.Link[2], 2, VecPos);
10901  }
10902  else if((TE.TrackType == Simple) || (TE.TrackType == Buffers) || (TE.TrackType == SignalPost) || (TE.TrackType == Continuation) ||
10903  (TE.TrackType == GapJump) || (TE.TrackType == FootCrossing))
10904  // need to list these explicitly since inactive elements will still be 'found' if there is an active element
10905  // at the same position
10906  {
10907  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
10909  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
10911  }
10912  }
10913  }
10915  ResetChangedFileDataAndCaption(22, false);
10916  // RlyFile = false; - don't alter this just for PrefDir changes
10917  Level1Mode = BaseMode; // call this first to clear everything, then set PrefDir mode
10918  SetLevel1Mode(30);
10920  SetLevel1Mode(31); // calls Clearand... to display all PrefDirs
10921  Utilities->CallLogPop(1549);
10922  }
10923  catch(const Exception &e)
10924  {
10925  ErrorLog(155, e.Message);
10926  }
10927 }
10928 
10929 // ---------------------------------------------------------------------------
10930 
10931 void __fastcall TInterface::CancelSelectionMenuItemClick(TObject *Sender)
10932 {
10933  try
10934  {
10935  TrainController->LogEvent("CancelSelectionClick");
10936  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelSelectionClick");
10937 // ClearandRebuildRailway(46); //called below
10938  SelectionValid = false;
10939  CancelSelectionFlag = true; // used to avoid RecoverClipboard in pasting when CutMoving selected
10940  Track->CopyFlag = false;
10942  if(Level1Mode == TrackMode)
10943  {
10944  SetLevel1Mode(76); // CancelSelectionFlag needed here
10946  SetLevel2TrackMode(68);
10947  }
10948  else if(Level1Mode == PrefDirMode)
10949  {
10950  SetLevel1Mode(32);
10951  }
10952  CancelSelectionFlag = false; // done with it
10953  ResetSelectRect();
10954  ClearandRebuildRailway(82); // to remove the selection outline
10955  Clipboard()->Clear();
10956  Clipboard()->Close();
10957  Utilities->CallLogPop(1413);
10958  }
10959  catch(const EClipboardException &e) // take no action //non-error catch
10960  {
10961 // Application->MessageBox(L"A clipboard error occurred in the cancel function", L"Message", MB_OK);
10962  TrainController->LogEvent("EClipboardException in CancelSelectionMenuItemClick - message = " + e.Message);
10963  Utilities->CallLogPop(2314);
10964  }
10965  catch(const Exception &e)
10966  {
10967  ErrorLog(156, e.Message);
10968  }
10969 }
10970 
10971 // ---------------------------------------------------------------------------
10972 
10973 void __fastcall TInterface::CheckPrefDirConflictsMenuItemClick(TObject *Sender)
10974 {
10975 //Conflicts consist of track elements without PDs, a preferred direction (PD) that links to a track element without a PD on it, or a PD that links to
10976 //another PD that is set in the wrong direction.
10977 
10978 //function changed to become more comprehensive at v2.13.0
10979  try
10980  {
10981  TrainController->LogEvent("CheckPrefDirConflictsMenuItemClick");
10982  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CheckPrefDirConflictsMenuItemClick");
10983  bool FoundFlag;
10984  int Count = 0;
10985  UnicodeString CountWord = "There are several track elements without preferred directions.\n\n"
10986  "Do you wish to highlight them (YES) or skip this part of the check (NO)?";
10987 
10988  int PD0, PD1, PD2, PD3, HLoc, VLoc, LastHLoc = -2000000, LastVLoc = -2000000; //well outside any conceivable range
10989  AnsiString TempInfo = InfoPanel->Caption;
10990  if(EveryPrefDir->PrefDirSize() <= 0)
10991  {
10992  ShowMessage("No preferred directions set.");
10993  Utilities->CallLogPop(2301);
10994  return;
10995  }
10996  else
10997  {
10998  InfoPanel->Visible = true;
10999  InfoPanel->Caption = "Checking preferred directions - please wait";
11000  InfoPanel->Update();
11001  THVShortPair LasTHVShortPair;
11002  LasTHVShortPair.first = -2000000;
11003  LasTHVShortPair.second = -2000000; //well outside any conceivable range
11004  Screen->Cursor = TCursor(-11); // Hourglass
11005 //check PDs, iterate the map rather than the vector so that pref dirs at the same H & V are consecutive, & can prevent the same element showing more than once
11006 
11007  for(TOnePrefDir::TPrefDir4MultiMapIterator PDMMIt = EveryPrefDir->PrefDir4MultiMap.begin(); PDMMIt != EveryPrefDir->PrefDir4MultiMap.end(); PDMMIt++)
11008  {
11009  bool ELinkFound = false;//, BiDir = false;
11010  int ELink = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetELink();
11011  int ELinkPos = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetELinkPos();
11012  int ThisElementHLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
11013  int ThisElementVLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
11014  if((ELink > -1) && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos] > -1))
11015  {
11017  Track->TrackElementAt(1024, EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos]).VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11018  if((EveryPrefDir->PrefDirVector.at(PDMMIt->second).TrackType == GapJump) && (ELinkPos == 0)) //0 is the gap position
11019  {
11020  if(PD0 > -1)
11021  {
11022  if(EveryPrefDir->PrefDirVector.at(PD0).TrackType == GapJump) //the corresponding gap
11023  {
11024  if(EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos() == 0) // entry link is at the gap end so it corresponds
11025  {
11026  ELinkFound = true;
11027  }
11028  }
11029  }
11030  if(PD1 > -1)
11031  {
11032  if(EveryPrefDir->PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
11033  {
11034  if(EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos() == 0) // entry link is at the gap end so it corresponds
11035  {
11036  ELinkFound = true;
11037  }
11038  }
11039  }
11040  }
11041  if(EveryPrefDir->BiDirectionalPrefDir(0, PDMMIt) &&
11042  (Track->TrackElementAt(1454, EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetTrackVectorPosition()).
11043  Config[EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetELinkPos()] == Signal))
11044  {
11045  ELinkFound = true; // ok if this element is a signal at exit end
11046  }
11047  if(BypassPDCrossoverMismatch(0, ThisElementHLoc, ThisElementVLoc))
11048  {
11049  ELinkFound = true; // ok to skip linked points with bidirs on both links and single PDs on other legs
11050  }
11051  if(PD0 > -1)
11052  {
11053  if(EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == (10 - ELink))
11054  {
11055  ELinkFound = true;
11056  }
11057  //ok if a signal at exit end of a single dir PD element for a conflict at the ELink end of a bidirectional PD element (applies for PD0 & 1 only)
11058  else if(EveryPrefDir->BiDirectionalPrefDir(1, PDMMIt) &&
11059  Track->TrackElementAt(1455, EveryPrefDir->PrefDirVector.at(PD0).GetTrackVectorPosition()).
11060  Config[EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos()] == Signal)
11061  {
11062  ELinkFound = true;
11063  }
11064  }
11065  if(PD1 > -1)
11066  {
11067  if(EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == (10 - ELink))
11068  {
11069  ELinkFound = true;
11070  }
11071  //as above ok if a signal at exit end of a single PD element for a conflict at the ELink end of a bidirectional PD element (applies for PD0 & 1 only)
11072  else if(EveryPrefDir->BiDirectionalPrefDir(2, PDMMIt) &&
11073  Track->TrackElementAt(1456, EveryPrefDir->PrefDirVector.at(PD0).GetTrackVectorPosition()).
11074  Config[EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos()] == Signal)
11075  {
11076  ELinkFound = true;
11077  }
11078  }
11079  if(PD2 > -1) //if PD2/3 > -1 then can'#t be a signal
11080  {
11081  if(EveryPrefDir->PrefDirVector.at(PD2).GetXLink() == (10 - ELink))
11082  {
11083  ELinkFound = true;
11084  }
11085  }
11086  if(PD3 > -1)
11087  {
11088  if(EveryPrefDir->PrefDirVector.at(PD3).GetXLink() == (10 - ELink))
11089  {
11090  ELinkFound = true;
11091  }
11092  }
11093  }
11094  if(!ELinkFound && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos] > -1))
11095  {
11096  HLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
11097  VLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
11098  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
11099  {
11100  LastHLoc = HLoc;
11101  LastVLoc = VLoc;
11102  while((Display->DisplayOffsetH - HLoc) > 0)
11103  {
11104  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
11105  }
11106  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
11107  {
11109  }
11110  while((Display->DisplayOffsetV - VLoc) > 0)
11111  {
11112  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
11113  }
11114  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
11115  {
11117  }
11119  Display->InvertElement(2, HLoc * 16, VLoc * 16);
11120  Screen->Cursor = TCursor(-2); // Arrow
11121  int Button = Application->MessageBox(L"Preferred direction missing or a mismatch at a link\n"
11122  "between the highlighted element and an adjacent element.\n\n"
11123  "The highlighted element may be behind this message\n"
11124  "which can be moved by left clicking the mouse in the\n"
11125  "title bar and dragging it.\n\n"
11126  "The omission/mismatch may or may not matter depending\n"
11127  "on routing requirements during operation.\n\n"
11128  "Click 'OK' to ignore and continue checking or 'Cancel'\n"
11129  "to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
11130  ClearandRebuildRailway(86); // to clear inversion
11131  if(Button == IDCANCEL)
11132  {
11133  InfoPanel->Caption = TempInfo;
11134  Utilities->CallLogPop(2303);
11135  return;
11136  }
11137  Screen->Cursor = TCursor(-11); //Hourglass
11138  Display->Update();
11139  }
11140  }
11141 
11142  bool XLinkFound = false;
11143  int XLink = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetXLink();
11144  int XLinkPos = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetXLinkPos();
11145  if((XLink > -1) && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos] > -1))
11146  {
11148  Track->TrackElementAt(1026, EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos]).VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11149  if((EveryPrefDir->PrefDirVector.at(PDMMIt->second).TrackType == GapJump) && (XLinkPos == 0)) //0 is the gap position
11150  {
11151  if(PD0 > -1)
11152  {
11153  if(EveryPrefDir->PrefDirVector.at(PD0).TrackType == GapJump) //the corresponding gap
11154  {
11155  if(EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos() == 0) // entry link is at the gap end so it corresponds
11156  {
11157  XLinkFound = true;
11158  }
11159  }
11160  }
11161  if(PD1 > -1)
11162  {
11163  if(EveryPrefDir->PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
11164  {
11165  if(EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos() == 0) // entry link is at the gap end so it corresponds
11166  {
11167  XLinkFound = true;
11168  }
11169  }
11170  }
11171  }
11172  if(EveryPrefDir->BiDirectionalPrefDir(3, PDMMIt) &&
11173  (Track->TrackElementAt(1457, EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetTrackVectorPosition()).
11174  Config[EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetXLinkPos()] == Signal))
11175  {
11176  XLinkFound = true; // ok if this element is a signal at exit end
11177  }
11178  if(BypassPDCrossoverMismatch(1, ThisElementHLoc, ThisElementVLoc))
11179  {
11180  XLinkFound = true; // ok to skip linked points with bidirs on both links and single PDs on other legs
11181  }
11182  if(PD0 > -1)
11183  {
11184  if(EveryPrefDir->PrefDirVector.at(PD0).GetELink() == (10 - XLink))
11185  {
11186  XLinkFound = true;
11187  }
11188  }
11189  if(PD1 > -1)
11190  {
11191  if(EveryPrefDir->PrefDirVector.at(PD1).GetELink() == (10 - XLink))
11192  {
11193  XLinkFound = true;
11194  }
11195  }
11196  if(PD2 > -1)
11197  {
11198  if(EveryPrefDir->PrefDirVector.at(PD2).GetELink() == (10 - XLink))
11199  {
11200  XLinkFound = true;
11201  }
11202  }
11203  if(PD3 > -1)
11204  {
11205  if(EveryPrefDir->PrefDirVector.at(PD3).GetELink() == (10 - XLink))
11206  {
11207  XLinkFound = true;
11208  }
11209  }
11210  }
11211  if(!XLinkFound && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos] > -1))
11212  {
11213  HLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
11214  VLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
11215  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
11216  {
11217  LastHLoc = HLoc;
11218  LastVLoc = VLoc;
11219  while((Display->DisplayOffsetH - HLoc) > 0)
11220  {
11221  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
11222  }
11223  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
11224  {
11226  }
11227  while((Display->DisplayOffsetV - VLoc) > 0)
11228  {
11229  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
11230  }
11231  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
11232  {
11234  }
11236  Display->InvertElement(3, HLoc * 16, VLoc * 16);
11237  Screen->Cursor = TCursor(-2); // Arrow
11238  int Button = Application->MessageBox(L"Preferred direction missing or a mismatch at a link\n"
11239  "between the highlighted element and an adjacent element.\n\n"
11240  "The highlighted element may be behind this message\n"
11241  "which can be moved by left clicking the mouse in the\n"
11242  "title bar and dragging it.\n\n"
11243  "The omission/mismatch may or may not matter depending\n"
11244  "on routing requirements during operation.\n\n"
11245  "Click 'OK' to ignore and continue checking or 'Cancel'\n"
11246  "to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
11247  ClearandRebuildRailway(88); // to clear inversion
11248  if(Button == IDCANCEL)
11249  {
11250  InfoPanel->Caption = TempInfo;
11251  Utilities->CallLogPop(2304);
11252  return;
11253  }
11254  Screen->Cursor = TCursor(-11); // Hourglass
11255  Display->Update();
11256  }
11257  }
11258  }
11259 //now check every track element to make sure there's a PD set on it. Get H&V for each, and if single track element ensure PD0 set, else make
11260 //sure both set, but first count them and if > 9 offer to skip
11261  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
11262  {
11263  int HLoc = Track->TrackElementAt(1470, x).HLoc;
11264  int VLoc = Track->TrackElementAt(1471, x).VLoc;
11265  if((Track->TrackElementAt(1472, x).TrackType == Points) || (Track->TrackElementAt(1473, x).TrackType == Crossover) ||
11266  (Track->TrackElementAt(1474, x).TrackType == Bridge))
11267  {
11268  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(34, HLoc, VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11269  //check if either track with no PDs: !Foundflag == none, PD1 == -1 == only one, and last condition covers one having a bidir PD & other none
11270  if(!FoundFlag) //none
11271  {
11272  Count += 2;
11273  }
11274  else if(PD1 == -1) // only one
11275  {
11276  Count++;
11277  }
11278  else if(((PD2 == -1) && (PD1 > -1) && (EveryPrefDir->PrefDirVector.at(PD1).GetELink() == EveryPrefDir->PrefDirVector.at(PD0).GetXLink()) &&
11279  (EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == EveryPrefDir->PrefDirVector.at(PD0).GetELink()))) //only one, other has bidirs
11280  {
11281  Count++;
11282  }
11283  }
11284  else //single track element
11285  {
11286  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(35, HLoc, VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11287  //check if either track with no PDs: !Foundflag == none, PD1 == -1 == only one, and last condition covers one having a bidir PD & other none
11288  if(!FoundFlag)
11289  {
11290  Count++;
11291  }
11292  }
11293  }
11294  if(Count > 20)
11295  {
11296  CountWord = "There are many track elements without preferred directions.\n\n"
11297  "Do you wish to highlight them (YES) or skip this part of the check (NO)?";
11298  }
11299  if(Count > 9)
11300  {
11301  Screen->Cursor = TCursor(-2); // Arrow
11302  int Button = Application->MessageBox(CountWord.c_str(), L"Skip option", MB_YESNO);
11303  ClearandRebuildRailway(96); // to clear inversion
11304  if(Button == IDNO)
11305  {
11306  InfoPanel->Caption = TempInfo;
11307  Utilities->CallLogPop(2484);
11308  return;
11309  }
11310  Screen->Cursor = TCursor(-11); //Hourglass
11311  Display->Update();
11312  }
11313 //continue with the check if haven't returned
11314  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
11315  {
11316  int HLoc = Track->TrackElementAt(1465, x).HLoc;
11317  int VLoc = Track->TrackElementAt(1466, x).VLoc;
11318  if((Track->TrackElementAt(1467, x).TrackType == Points) || (Track->TrackElementAt(1468, x).TrackType == Crossover) ||
11319  (Track->TrackElementAt(1469, x).TrackType == Bridge))
11320  {
11321  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(32, HLoc, VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11322  //check if either track with no PDs: !Foundflag == none, PD1 == -1 == only one, and last condition covers one having a bidir PD & other none
11323  if(!FoundFlag || (PD1 == -1) || ((PD2 == -1) && (PD1 > -1) && (EveryPrefDir->PrefDirVector.at(PD1).GetELink() == EveryPrefDir->PrefDirVector.at(PD0).GetXLink()) &&
11324  (EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == EveryPrefDir->PrefDirVector.at(PD0).GetELink()))) //need to check both as points can meet just one with one PD on each track
11325  {
11326  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
11327  {
11328  LastHLoc = HLoc;
11329  LastVLoc = VLoc;
11330  while((Display->DisplayOffsetH - HLoc) > 0)
11331  {
11332  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
11333  }
11334  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
11335  {
11337  }
11338  while((Display->DisplayOffsetV - VLoc) > 0)
11339  {
11340  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
11341  }
11342  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
11343  {
11345  }
11347  Display->InvertElement(4, HLoc * 16, VLoc * 16);
11348  Screen->Cursor = TCursor(-2); // Arrow
11349  int Button = Application->MessageBox(L"Preferred direction mismatch at a link between the\n"
11350  "highlighted element and an adjacent element.\n\n"
11351  "The highlighted element may be behind this message\n"
11352  "which can be moved by left clicking the mouse in the\n"
11353  "title bar and dragging it.\n\n"
11354  "The mismatch may or may not matter depending on\n"
11355  "routing requirements during operation.\n\n"
11356  "Click 'OK' to ignore and continue checking or 'Cancel'\n"
11357  "to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
11358  ClearandRebuildRailway(93); // to clear inversion
11359  if(Button == IDCANCEL)
11360  {
11361  InfoPanel->Caption = TempInfo;
11362  Utilities->CallLogPop(2482);
11363  return;
11364  }
11365  Screen->Cursor = TCursor(-11); //Hourglass
11366  Display->Update();
11367  }
11368  }
11369  }
11370  else //single track element
11371  {
11372  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(33, HLoc, VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11373  //check if either track with no PDs: !Foundflag == none, PD1 == -1 == only one, and last condition covers one having a bidir PD & other none
11374  if(!FoundFlag)
11375  {
11376  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
11377  {
11378  LastHLoc = HLoc;
11379  LastVLoc = VLoc;
11380  while((Display->DisplayOffsetH - HLoc) > 0)
11381  {
11382  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
11383  }
11384  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
11385  {
11387  }
11388  while((Display->DisplayOffsetV - VLoc) > 0)
11389  {
11390  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
11391  }
11392  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
11393  {
11395  }
11397  Display->InvertElement(5, HLoc * 16, VLoc * 16);
11398  Screen->Cursor = TCursor(-2); // Arrow
11399  int Button = Application->MessageBox(L"Preferred direction mismatch at a link between the\n"
11400  "highlighted element and an adjacent element.\n\n"
11401  "The highlighted element may be behind this message\n"
11402  "which can be moved by left clicking the mouse in the\n"
11403  "title bar and dragging it.\n\n"
11404  "The mismatch may or may not matter depending on\n"
11405  "routing requirements during operation.\n\n"
11406  "Click 'OK' to ignore and continue checking or 'Cancel'\n"
11407  "to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
11408  ClearandRebuildRailway(95); // to clear inversion
11409  if(Button == IDCANCEL)
11410  {
11411  InfoPanel->Caption = TempInfo;
11412  Utilities->CallLogPop(2483);
11413  return;
11414  }
11415  Screen->Cursor = TCursor(-11); //Hourglass
11416  Display->Update();
11417  }
11418  }
11419  }
11420  }
11421  }
11422  Screen->Cursor = TCursor(-2); // Arrow
11423  ShowMessage("Finished");
11424  InfoPanel->Caption = TempInfo;
11425  Utilities->CallLogPop(2305);
11426  }
11427  catch(const Exception &e) //non-error catch
11428  {
11429  Screen->Cursor = TCursor(-2); // Arrow
11430  ShowMessage("Error in preferred direction checking, unable to complete the check");
11431  Utilities->CallLogPop(2306);
11432  }
11433 }
11434 
11435 //---------------------------------------------------------------------------
11436 
11437 bool TInterface::BypassPDCrossoverMismatch(int Caller, int HLoc, int VLoc)
11438 /* If there's a crossover between two lines that each have single PDs set on them and the crossover has bidirectioal PDs then ordinarily a mismatch would be flagged
11439 for each crossover. However since no PD route can be set over the crossover whatever PDs are set on them there's no point in flagging the mismatch.
11440 This function checks if the element passed in is a point with 3 PDs set (PD2 > -1 & PD3 == -1), i.e. only one leg has a bidir PD, and that this bidir PD leg is connected
11441 to another point bidir leg with 3 PDs set. If so it returns true, else false.
11442 */
11443 {
11444  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BypassPDCrossoverMismatch " + AnsiString(HLoc) + "," + AnsiString(VLoc));
11445  int PD0 = -1, PD1 = -1, PD2 = -1, PD3 = -1;
11446  int PDLinked0 = -1, PDLinked1 = -1, PDLinked2 = -1, PDLinked3 = -1;
11447  int BidirLinkPos = -1;
11448  bool FoundFlag = false, BidirOnLink = false;
11449  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(19, HLoc, VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11450  if((PD0 == -1) || (PD2 == -1) || (PD3 > -1))
11451  {
11452  Utilities->CallLogPop(2457);
11453  return false;
11454  }
11455  if(PD0 > -1)
11456  {
11457  if(EveryPrefDir->PrefDirVector.at(PD0).TrackType != Points)
11458  {
11459  Utilities->CallLogPop(2458);
11460  return false;
11461  }
11462  }
11463 //here it's points with one bidir leg
11464 //now find the link [1] or [3] that corresponds to the bidir leg and check it's another point with the same characteristics
11465  if((EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == EveryPrefDir->PrefDirVector.at(PD1).GetELink()) &&
11466  (EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == EveryPrefDir->PrefDirVector.at(PD0).GetELink()))
11467  { // bidir leg is PD0 & PD1
11468  if(EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos() == 1)
11469  {
11470  BidirLinkPos = 1;
11471  }
11472  else if(EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos() == 3)
11473  {
11474  BidirLinkPos = 3;
11475  }
11476  else if(EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos() == 1)
11477  {
11478  BidirLinkPos = 1;
11479  }
11480  else if(EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos() == 3)
11481  {
11482  BidirLinkPos = 3;
11483  }
11484  }
11485  else if((EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == EveryPrefDir->PrefDirVector.at(PD2).GetELink()) &&
11486  (EveryPrefDir->PrefDirVector.at(PD2).GetXLink() == EveryPrefDir->PrefDirVector.at(PD0).GetELink()))
11487  { // bidir leg is PD0 & PD2
11488  if(EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos() == 1)
11489  {
11490  BidirLinkPos = 1;
11491  }
11492  else if(EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos() == 3)
11493  {
11494  BidirLinkPos = 3;
11495  }
11496  else if(EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos() == 1)
11497  {
11498  BidirLinkPos = 1;
11499  }
11500  else if(EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos() == 3)
11501  {
11502  BidirLinkPos = 3;
11503  }
11504  }
11505  else if((EveryPrefDir->PrefDirVector.at(PD2).GetXLink() == EveryPrefDir->PrefDirVector.at(PD1).GetELink()) &&
11506  (EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == EveryPrefDir->PrefDirVector.at(PD2).GetELink()))
11507  { // bidir leg is PD1 & PD2
11508  if(EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos() == 1)
11509  {
11510  BidirLinkPos = 1;
11511  }
11512  else if(EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos() == 3)
11513  {
11514  BidirLinkPos = 3;
11515  }
11516  else if(EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos() == 1)
11517  {
11518  BidirLinkPos = 1;
11519  }
11520  else if(EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos() == 3)
11521  {
11522  BidirLinkPos = 3;
11523  }
11524  }
11525  if((BidirLinkPos == -1) || (BidirLinkPos > 3))//shouldn't be
11526  {
11527  Utilities->CallLogPop(2459);
11528  return false;
11529  }
11530 //now find the linked element and check it's a point with 3 PDs set & link bidir
11531  int TVPos = Track->TrackElementAt(1458, EveryPrefDir->PrefDirVector.at(PD0).GetTrackVectorPosition()).Conn[BidirLinkPos];
11532  int TVLinkPos = Track->TrackElementAt(1459, EveryPrefDir->PrefDirVector.at(PD0).GetTrackVectorPosition()).ConnLinkPos[BidirLinkPos];
11533  if(TVPos == -1)
11534  {
11535  Utilities->CallLogPop(2460);
11536  return false;
11537  }
11538  if((TVLinkPos == 0) || (TVLinkPos == 2) || (TVLinkPos > 3))
11539  {
11540  Utilities->CallLogPop(2461);
11541  return false;
11542  }
11543  if(Track->TrackElementAt(1460, TVPos).TrackType != Points)
11544  {
11545  Utilities->CallLogPop(2462);
11546  return false;
11547  }
11548  if((TVLinkPos != 1) && (TVLinkPos != 3)) //must be linked at trailing leg
11549  {
11550  Utilities->CallLogPop(2463);
11551  return false;
11552  }
11554  Track->TrackElementAt(1461, TVPos).VLoc, FoundFlag, PDLinked0, PDLinked1, PDLinked2, PDLinked3);
11555  if(!FoundFlag)
11556  {
11557  Utilities->CallLogPop(2464);
11558  return false;
11559  }
11560  if((PDLinked0 == -1) || (PDLinked2 == -1) || (PDLinked3 > -1)) //must have exactly 3 PDs
11561  {
11562  Utilities->CallLogPop(2465);
11563  return false;
11564  }
11565 //now need bidir PDs on linked leg
11566  if((EveryPrefDir->PrefDirVector.at(PDLinked0).GetXLink() == EveryPrefDir->PrefDirVector.at(PDLinked1).GetELink()) &&
11567  (EveryPrefDir->PrefDirVector.at(PDLinked0).GetELink() == EveryPrefDir->PrefDirVector.at(PDLinked1).GetXLink()))
11568  { //bidir leg is PDLinked0 & PDLinked1
11569  if(EveryPrefDir->PrefDirVector.at(PDLinked0).GetXLinkPos() == TVLinkPos)
11570  {
11571  BidirOnLink = true;
11572  }
11573  if(EveryPrefDir->PrefDirVector.at(PDLinked0).GetELinkPos() == TVLinkPos)
11574  {
11575  BidirOnLink = true;
11576  }
11577 
11578  }
11579  else if((EveryPrefDir->PrefDirVector.at(PDLinked0).GetXLink() == EveryPrefDir->PrefDirVector.at(PDLinked2).GetELink()) &&
11580  (EveryPrefDir->PrefDirVector.at(PDLinked0).GetELink() == EveryPrefDir->PrefDirVector.at(PDLinked2).GetXLink()))
11581  { //bidir leg is PDLinked0 & PDLinked2
11582  if(EveryPrefDir->PrefDirVector.at(PDLinked0).GetXLinkPos() == TVLinkPos)
11583  {
11584  BidirOnLink = true;
11585  }
11586  if(EveryPrefDir->PrefDirVector.at(PDLinked0).GetELinkPos() == TVLinkPos)
11587  {
11588  BidirOnLink = true;
11589  }
11590 
11591  }
11592  else if((EveryPrefDir->PrefDirVector.at(PDLinked1).GetXLink() == EveryPrefDir->PrefDirVector.at(PDLinked2).GetELink()) &&
11593  (EveryPrefDir->PrefDirVector.at(PDLinked1).GetELink() == EveryPrefDir->PrefDirVector.at(PDLinked2).GetXLink()))
11594  { //bidir leg is PDLinked0 & PDLinked2
11595  if(EveryPrefDir->PrefDirVector.at(PDLinked1).GetXLinkPos() == TVLinkPos)
11596  {
11597  BidirOnLink = true;
11598  }
11599  if(EveryPrefDir->PrefDirVector.at(PDLinked1).GetELinkPos() == TVLinkPos)
11600  {
11601  BidirOnLink = true;
11602  }
11603  }
11604  if(!BidirOnLink)
11605  {
11606  Utilities->CallLogPop(2466);
11607  return false;
11608  }
11609  Utilities->CallLogPop(2467);
11610  return true;
11611 }
11612 
11613 //---------------------------------------------------------------------------
11614 
11615 void __fastcall TInterface::LoadTimetableMenuItemClick(TObject *Sender)
11616 {
11617  try
11618  {
11619  TrainController->LogEvent("LoadTimetableMenuItemClick");
11620  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadTimetableMenuItemClick");
11621  TimetableDialog->Filter = "Timetable file (*.ttb)|*.ttb";
11622  // reset all message flags, stops them being given twice new at v2.4.0
11623  TrainController->SSHigh = false;
11624  TrainController->MRSHigh = false;
11625  TrainController->MRSLow = false;
11626  TrainController->MassHigh = false;
11627  TrainController->BFHigh = false;
11628  TrainController->BFLow = false;
11629  TrainController->PwrHigh = false;
11630  TrainController->SigSHigh = false;
11631  TrainController->SigSLow = false;
11632  if(TimetableDialog->Execute())
11633  {
11634  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName)) // new at v2.6.0 to retain a new directory
11635  {
11636  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
11637  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
11638  }
11639  TrainController->LogEvent("LoadTimetable " + TimetableDialog->FileName);
11640  bool CheckLocationsExistInRailwayTrue = true;
11641  if(TrainController->TimetableIntegrityCheck(0, AnsiString(TimetableDialog->FileName).c_str(), true, CheckLocationsExistInRailwayTrue))
11642  // true for GiveMessages
11643  {
11644  Screen->Cursor = TCursor(-11); // Hourglass;
11645  std::ifstream TTBLFile(AnsiString(TimetableDialog->FileName).c_str(), std::ios_base::binary);
11646  if(TTBLFile.is_open())
11647  {
11648  bool SessionFileFalse = false;
11649  if(BuildTrainDataVectorForLoadFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue, SessionFileFalse)) // true for GiveMessages
11650  {
11651  SaveTempTimetableFile(0, TimetableDialog->FileName);
11652  } // don't need an 'else' as messages given in BuildTrainDataVectorForLoadFile
11653 
11654  }
11655  else
11656  {
11657  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
11658  }
11659  Screen->Cursor = TCursor(-2); // Arrow
11660  } // if(TimetableIntegrityCheck
11661  else
11662  {
11663  ShowMessage("Timetable integrity check failed - unable to load " + TimetableDialog->FileName + ". Please check that the file exists and is spelled correctly.");
11664  }
11665  } // if(TimetableDialog->Execute())
11666 
11667  // else ShowMessage("Load Aborted");
11668  Utilities->CallLogPop(752);
11669  }
11670  catch(const Exception &e)
11671  {
11672  ErrorLog(34, e.Message);
11673  }
11674 }
11675 
11676 // ---------------------------------------------------------------------------
11677 void __fastcall TInterface::TakeSignallerControlMenuItemClick(TObject *Sender)
11678 {
11679  try
11680  {
11681  TrainController->LogEvent("SignallerControl1Click");
11682  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControl1Click");
11684  Train.SignallerStoppingFlag = false;
11685  Train.TrainMode = Signaller;
11686  if(Train.MaxRunningSpeed > Train.SignallerMaxSpeed)
11687  {
11688  Train.MaxRunningSpeed = Train.SignallerMaxSpeed;
11689  }
11690  if(Train.Stopped())
11691  {
11692  Train.SignallerStopped = true; // condition added at v2.4.0 to allow for taking sig control of failed moving trains
11693  }
11694  Train.CallingOnFlag = false; // in case was set, wouldn't start anyway if called on as SignallerStopped = true
11696  Train.PlotTrain(5, Display);
11697  AnsiString LocName = "";
11698  if(Train.LeadElement > -1)
11699  {
11700  LocName = Track->TrackElementAt(633, Train.LeadElement).ActiveTrackElementName;
11701  }
11702  if((LocName == "") && (Train.MidElement > -1))
11703  {
11704  LocName = Track->TrackElementAt(634, Train.MidElement).ActiveTrackElementName;
11705  }
11706  // store the value that allow restoration of tt control or not - RestoreTimetableLocation
11707  if(Train.RevisedStoppedAtLoc() && (LocName != ""))
11708  {
11709  Train.RestoreTimetableLocation = LocName;
11710  }
11711  else
11712  {
11713  Train.RestoreTimetableLocation = "";
11714  }
11715  // check whether need to offer 'pass red signal'
11716  if(!Train.StoppedAtSignal && Train.RevisedStoppedAtLoc())
11717  {
11718  int NextElementPosition = Track->TrackElementAt(775, Train.LeadElement).Conn[Train.LeadExitPos];
11719  int NextEntryPos = Track->TrackElementAt(776, Train.LeadElement).ConnLinkPos[Train.LeadExitPos];
11720  if((NextElementPosition > -1) && (NextEntryPos > -1))
11721  {
11722  if((Track->TrackElementAt(777, NextElementPosition).Config[Track->GetNonPointsOppositeLinkPos(NextEntryPos)] == Signal) &&
11723  (Track->TrackElementAt(778, NextElementPosition).Attribute == 0))
11724  {
11725  // set both StoppedAtLocation & StoppedAtSignal, so that 'pass red signal' is offered in popup menu rather than move
11726  // forwards, but don't change the background colour so still shows as stopped at location
11727  Train.StoppedAtSignal = true;
11728  }
11729  }
11730  }
11731  // find element ID if no locname
11732  if((LocName == "") && Train.LeadElement > -1)
11733  {
11734  LocName = Track->TrackElementAt(635, Train.LeadElement).ElementID;
11735  }
11736  if((LocName == "") && (Train.MidElement > -1))
11737  {
11738  LocName = Track->TrackElementAt(636, Train.MidElement).ElementID;
11739  }
11740  Train.LogAction(0, Train.HeadCode, "", TakeSignallerControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11741  Utilities->CallLogPop(1772);
11742  }
11743  catch(const Exception &e)
11744  {
11745  ErrorLog(157, e.Message);
11746  }
11747 }
11748 
11749 // ---------------------------------------------------------------------------
11750 
11751 void __fastcall TInterface::TimetableControlMenuItemClick(TObject *Sender)
11752 {
11753  try
11754  {
11755  TrainController->LogEvent("TimetableControlMenuItemClick");
11756  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableControlMenuItemClick");
11758  Train.SignallerStoppingFlag = false;
11759  Train.TrainMode = Timetable;
11760  Train.SignallerStopped = false;
11761  Train.StoppedAfterSPAD = false;
11762  Train.SPADFlag = false;
11765 // red headcode[0]
11766  Train.PlotTrain(6, Display);
11767  AnsiString LocName = "", LeadElementLocName = "", MidElementLocName = "", RequiredLocName = Train.ActionVectorEntryPtr->LocationName;
11768  if(Train.LeadElement > -1) //this naming procedure changed at v2.9.1 as a train might have one element at a station and the other at a non-station named location
11769  //but only one is the location in the timetable, and that is the RequiredLocName. Discovered for LS41 at Lincoln.
11770  {
11771  LeadElementLocName = Track->TrackElementAt(645, Train.LeadElement).ActiveTrackElementName;
11772  }
11773  if(Train.MidElement > -1)
11774  {
11775  MidElementLocName = Track->TrackElementAt(647, Train.MidElement).ActiveTrackElementName;
11776  }
11777  if((LeadElementLocName == "") && (MidElementLocName == "") && (Train.LeadElement > -1))
11778  {
11779  LeadElementLocName = Track->TrackElementAt(646, Train.LeadElement).ElementID;
11780  }
11781  if((MidElementLocName == "") && (Train.MidElement > -1)) //changed from LeadElementLocName at v2.12.0 - must have been a mistake
11782  {
11783  MidElementLocName = Track->TrackElementAt(648, Train.MidElement).ElementID;
11784  }
11785  if((LeadElementLocName == RequiredLocName) || (MidElementLocName == RequiredLocName))
11786  {
11787  LocName = RequiredLocName;
11788  }
11789  else if(LeadElementLocName != "") //these two else ifs added at v2.12.0 as noticed that if a train is restored to tt control at
11790  { //a loc that isn't RequiredLocName then LocName is ""
11791  LocName = LeadElementLocName; //LeadElement takes precedence if both named
11792  }
11793  else if(MidElementLocName != "")
11794  {
11795  LocName = MidElementLocName;
11796  }
11798  {//Train.TreatPassAsTimeLocDeparture added at v2.12.0 so background stays pale green after taking signaller control, as LocationType is EnRoute for a Pass
11799  if(Train.TreatPassAsTimeLocDeparture) //this if... else... segment added at v2.12.0 to ensure one or the other true but not both
11800  {
11801  Train.StoppedAtLocation = false;
11802  }
11803  else
11804  {
11805  Train.StoppedAtLocation = true;
11806  }
11807  Train.StoppedAtSignal = false;
11808 // added at v2.7.0 as if had been stopped at signal before tt control restored then background colour would change to normal when signal cleared even when not due to depart
11809  Train.LastActionTime = TrainController->TTClockTime; // by itself this only affects trains that have still to arrive, if waiting to
11810  // depart the departure time & TRS time have already been calculated so need to
11811  // force a recalculation - see below
11812  Train.DepartureTimeSet = false; // force it to be recalculated based on new LastActionTime (if waiting to arrive this is false anyway)
11813  if(!Train.TrainFailed)
11814  {
11816  } // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11817 
11818  if((Train.ActionVectorEntryPtr->FormatType == TimeLoc) && (Train.ActionVectorEntryPtr->ArrivalTime >= TDateTime(0)))
11819  {
11820  // Timetable indicates that train still waiting to arrive for a TimeLoc arrival so send message and mark as arrived
11821  Train.LogAction(28, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
11822  Train.ActionVectorEntryPtr++; // advance pointer past arrival //added at v1.2.0
11823  }
11824  else if((Train.ActionVectorEntryPtr->FormatType == TimeTimeLoc) && !(Train.TimeTimeLocArrived))
11825  {
11826  // Timetable indicates that train still waiting to arrive for a TimeTimeLoc arrival so send message and mark as arrived
11827  Train.LogAction(29, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
11828  Train.TimeTimeLocArrived = true;
11829  // NB: No need for 'Train.ActionVectorEntryPtr++' because still to act on the departure time
11830  }
11831  }
11832  else
11833  {
11834  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas' error
11835  int NextEntryPos = -1; // ---ditto---
11836  if(Train.LeadElement > -1) // ---ditto---
11837  {
11838  // ---ditto---
11839  NextElementPos = Track->TrackElementAt(658, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
11840  NextEntryPos = Track->TrackElementAt(659, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
11841  } // ---ditto---
11842 
11843  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11844  if(!Train.TrainFailed)
11845  {
11846  Train.PlotTrainWithNewBackgroundColour(31, clNormalBackground, Display); // to remove other background if was present, moved from
11847  } // within Train.AbleToMove at v2.4.0 to cancel signal stop background
11848 
11849  if(Train.AbleToMove(1)) // if has no power
11850  {
11851  Train.EntrySpeed = 0; // moved from below for v1.3.2 after Carwyn Thomas error
11852  Train.EntryTime = TrainController->TTClockTime; // ---Ditto---
11853  Train.FirstHalfMove = true; // ---Ditto---
11854  if((NextElementPos > -1) && (NextEntryPos > -1)) // changed from if(NextElementPos >= 0) as above
11855  {
11856  // Train.EntrySpeed = 0;
11857  // Train.EntryTime = TrainController->TTClockTime;
11858  // Train.FirstHalfMove = true;
11859  Train.SetTrainMovementValues(15, NextElementPos, NextEntryPos);
11860  }
11861  // else follow the continuations //added these 3 conditions for v1.3.2 after Carwyn Thomas error
11862  else if((Train.LeadElement > -1) && (Track->TrackElementAt(894, Train.LeadElement).TrackType == Continuation))
11863  {
11864  Train.SetTrainMovementValues(21, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
11865  }
11866  else if((Train.MidElement > -1) && (Track->TrackElementAt(895, Train.MidElement).TrackType == Continuation))
11867  {
11868  Train.SetTrainMovementValues(22, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
11869  }
11870  else if((Train.LagElement > -1) && (Track->TrackElementAt(896, Train.LagElement).TrackType == Continuation))
11871  {
11872  Train.SetTrainMovementValues(23, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
11873  }
11874  }
11875  else if(Train.StoppedAtSignal)
11876  {
11877  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11878  if(!Train.TrainFailed)
11879  {
11881  }
11882  // TrainController->LogActionError(42, Train.HeadCode, "", SignalHold, Track->TrackElementAt(757, NextElementPos).ElementID);
11883  }
11884  }
11885  Train.LogAction(1, Train.HeadCode, "", RestoreTimetableControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11886  Utilities->CallLogPop(1195);
11887  }
11888  catch(const Exception &e)
11889  {
11890  ErrorLog(158, e.Message);
11891  }
11892 }
11893 
11894 // ---------------------------------------------------------------------------
11895 
11896 void __fastcall TInterface::ChangeDirectionMenuItemClick(TObject *Sender)
11897 {
11898  try
11899  {
11900  TrainController->LogEvent("ChangeDirectionMenuItemClick");
11901  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ChangeDirectionMenuItemClick");
11903  Train.SignallerStoppingFlag = false;
11904  Train.SignallerChangeTrainDirection(0); // this unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd
11905  Train.SignallerStopped = true;
11906  AnsiString LocName = "";
11907  if(Train.LeadElement > -1)
11908  {
11909  LocName = Track->TrackElementAt(637, Train.LeadElement).ActiveTrackElementName;
11910  }
11911  if((LocName == "") && (Train.MidElement > -1))
11912  {
11913  LocName = Track->TrackElementAt(638, Train.MidElement).ActiveTrackElementName;
11914  }
11915  if((LocName == "") && Train.LeadElement > -1)
11916  {
11917  LocName = Track->TrackElementAt(639, Train.LeadElement).ElementID;
11918  }
11919  if((LocName == "") && (Train.MidElement > -1))
11920  {
11921  LocName = Track->TrackElementAt(640, Train.MidElement).ElementID;
11922  }
11923  Train.LogAction(2, Train.HeadCode, "", SignallerChangeDirection, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11924  Utilities->CallLogPop(1196);
11925  }
11926  catch(const Exception &e)
11927  {
11928  ErrorLog(159, e.Message);
11929  }
11930 }
11931 // ---------------------------------------------------------------------------
11932 
11933 void __fastcall TInterface::MoveForwardsMenuItemClick(TObject *Sender)
11934 {
11935  try
11936  {
11937  TrainController->LogEvent("MoveForwardsMenuItemClick");
11938  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveForwardsMenuItemClick");
11940  Train.SignallerStoppingFlag = false;
11941  if(!Train.AbleToMove(2))
11942  {
11943  // shouldn't be here as when unable to move MoveForwards shouldn't be enabled, but leave in as a precaution
11944  Utilities->CallLogPop(1197);
11945  return;
11946  }
11947  Train.SignallerStopped = false;
11948  Train.StoppedAfterSPAD = false; // in case had been set
11949  Train.SPADFlag = false;
11950  Train.StoppedAtLocation = false; // may not have been set but reset anyway
11951  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11953  Train.EntrySpeed = 0;
11955  Train.FirstHalfMove = true;
11956  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
11957  int NextEntryPos = -1; // ---ditto---
11958  if(Train.LeadElement > -1) // ---ditto---
11959  {
11960  // ---ditto---
11961  NextElementPos = Track->TrackElementAt(652, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
11962  NextEntryPos = Track->TrackElementAt(657, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
11963  } // ---ditto---
11964 
11965  if((NextElementPos > -1) && (NextEntryPos > -1))
11966  {
11967  Train.SetTrainMovementValues(14, NextElementPos, NextEntryPos); // NextElement is the element to be entered
11968  }
11969  // else follow the continuations
11970  else if((Train.LeadElement > -1) && (Track->TrackElementAt(784, Train.LeadElement).TrackType == Continuation))
11971  {
11972  Train.SetTrainMovementValues(17, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
11973  }
11974  else if((Train.MidElement > -1) && (Track->TrackElementAt(785, Train.MidElement).TrackType == Continuation))
11975  {
11976  Train.SetTrainMovementValues(18, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
11977  }
11978  else if((Train.LagElement > -1) && (Track->TrackElementAt(786, Train.LagElement).TrackType == Continuation))
11979  {
11980  Train.SetTrainMovementValues(19, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
11981  }
11982  Train.LogAction(3, Train.HeadCode, "", SignallerMoveForwards, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11983  Utilities->CallLogPop(1198);
11984  }
11985  catch(const Exception &e)
11986  {
11987  ErrorLog(160, e.Message);
11988  }
11989 }
11990 // ---------------------------------------------------------------------------
11991 
11992 void __fastcall TInterface::SignallerJoinedByMenuItemClick(TObject *Sender)
11993 {
11994  // new at v2.4.0
11995  try
11996  {
11997  TrainController->LogEvent("JoinedByMenuItemClick");
11998  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinedByMenuItemClick");
11999  TTrain *TrainToBeJoinedBy;
12001  if(ThisTrain.IsThereAnAdjacentTrain(1, TrainToBeJoinedBy)) // this must come before both powers zero check in order to set a valid TrainToBeJoinedBy
12002  {
12003  if(TrainToBeJoinedBy->TrainMode != Signaller)
12004  {
12005  TrainController->StopTTClockMessage(91, "Adjacent train must be under signaller control in order to join");
12006  Utilities->CallLogPop(2156);
12007  return;
12008  }
12009  // here if there is an adjacent train under signaller control
12010  if((TrainToBeJoinedBy->PowerAtRail < 1) && (ThisTrain.PowerAtRail < 1))
12011  {
12012  ShowMessage("Can't join two trains when both are without power");
12013  Utilities->CallLogPop(2157);
12014  return;
12015  }
12016  AnsiString TrainToBeJoinedByHeadCode = TrainToBeJoinedBy->HeadCode;
12017  // set new values for mass etc
12018  double OtherBrakeForce = TrainToBeJoinedBy->MaxBrakeRate * TrainToBeJoinedBy->Mass;
12019  double OwnBrakeForce = ThisTrain.MaxBrakeRate * ThisTrain.Mass;
12020  double CombinedBrakeRate = (OtherBrakeForce + OwnBrakeForce) / (TrainToBeJoinedBy->Mass + ThisTrain.Mass);
12021 
12022  // set new values for mass etc
12023  if(ThisTrain.MaxRunningSpeed > TrainToBeJoinedBy->MaxRunningSpeed) //this added at v2.11.1 as had been omitted before
12024  {
12025  ThisTrain.MaxRunningSpeed = TrainToBeJoinedBy->MaxRunningSpeed;
12026  }
12027  ThisTrain.Mass += TrainToBeJoinedBy->Mass;
12028  ThisTrain.MaxBrakeRate = CombinedBrakeRate;
12029  ThisTrain.PowerAtRail += TrainToBeJoinedBy->PowerAtRail;
12030  ThisTrain.AValue = sqrt(2 * ThisTrain.PowerAtRail / ThisTrain.Mass);
12031 
12032  TrainToBeJoinedBy->TrainGone = true; // this will cause other train to be deleted
12033  TrainToBeJoinedBy->JoinedOtherTrainFlag = true;
12034  AnsiString LocName = "";
12035  if(ThisTrain.LeadElement > -1)
12036  {
12037  LocName = Track->TrackElementAt(979, ThisTrain.LeadElement).ActiveTrackElementName;
12038  }
12039  if((LocName == "") && (ThisTrain.MidElement > -1))
12040  {
12041  LocName = Track->TrackElementAt(980, ThisTrain.MidElement).ActiveTrackElementName;
12042  }
12043  if((LocName == "") && ThisTrain.LeadElement > -1)
12044  {
12045  LocName = Track->TrackElementAt(981, ThisTrain.LeadElement).ElementID;
12046  }
12047  if((LocName == "") && (ThisTrain.MidElement > -1))
12048  {
12049  LocName = Track->TrackElementAt(982, ThisTrain.MidElement).ElementID;
12050  }
12051  ThisTrain.StoppedWithoutPower = true;
12052  if(ThisTrain.PowerAtRail >= 1)
12053  {
12054  ThisTrain.StoppedWithoutPower = false;
12055  }
12056  ThisTrain.TrainFailed = false; // if had failed then no longer failed, even if joining train has no power
12057  if(!ThisTrain.RevisedStoppedAtLoc())
12058  {
12059  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
12061  }
12062  else
12063  {
12064  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
12066  }
12067  ThisTrain.SignallerStopped = true; // maybe as well as stopped without power, thought that takes precedence in floating window
12068  ThisTrain.LogAction(34, ThisTrain.HeadCode, TrainToBeJoinedBy->HeadCode, SignallerJoin, LocName, TDateTime(0), false); // TDateTime isn't used
12069  ThisTrain.ZeroPowerNoFrontSplitMessage = false; // added at v2.4.0, no need to include TrainToBeJoinedBy as that will be removed
12070  ThisTrain.ZeroPowerNoRearSplitMessage = false;
12071  ThisTrain.FailedTrainNoFinishJoinMessage = false;
12072  ThisTrain.ZeroPowerNoJoinedByMessage = false;
12073  ThisTrain.ZeroPowerNoCDTMessage = false;
12074  ThisTrain.ZeroPowerNoNewServiceMessage = false;
12076  ThisTrain.ZeroPowerNoRepeatShuttleMessage = false;
12078  Utilities->CallLogPop(2158);
12079  }
12080  }
12081  catch(const Exception &e)
12082  {
12083  ErrorLog(207, e.Message);
12084  }
12085 }
12086 // ---------------------------------------------------------------------------
12087 
12088 void __fastcall TInterface::RepairFailedTrainMenuItemClick(TObject *Sender)
12089 {
12090  // added at v2.4.0
12091  try
12092  {
12093  TrainController->LogEvent("RepairFailedTrainMenuItemClick");
12094  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedTrainMenuItemClick");
12096  Train.TrainFailed = false;
12097  Train.StoppedWithoutPower = false;
12098  Train.SignallerStopped = true;
12099  if(!Train.RevisedStoppedAtLoc())
12100  {
12101  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
12103  }
12104  else
12105  {
12106  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
12108  }
12109  Train.PowerAtRail = Train.OriginalPowerAtRail; // recover from original value, new at v2.4.0
12110  Train.AValue = sqrt(2 * Train.PowerAtRail / Train.Mass);
12111  Train.SetTrainMovementValues(24, Train.LeadElement, Train.LeadEntryPos);
12112  AnsiString LocName = "";
12113  if(Train.LeadElement > -1)
12114  {
12115  LocName = Track->TrackElementAt(983, Train.LeadElement).ActiveTrackElementName;
12116  }
12117  if((LocName == "") && (Train.MidElement > -1))
12118  {
12119  LocName = Track->TrackElementAt(984, Train.MidElement).ActiveTrackElementName;
12120  }
12121  if((LocName == "") && Train.LeadElement > -1)
12122  {
12123  LocName = Track->TrackElementAt(985, Train.LeadElement).ElementID;
12124  }
12125  if((LocName == "") && (Train.MidElement > -1))
12126  {
12127  LocName = Track->TrackElementAt(986, Train.MidElement).ElementID;
12128  }
12129  Train.LogAction(35, Train.HeadCode, "", RepairFailedTrain, LocName, TrainController->TTClockTime, false); // false for no warning
12130  Train.ZeroPowerNoFrontSplitMessage = false;
12131  Train.ZeroPowerNoRearSplitMessage = false;
12132  Train.FailedTrainNoFinishJoinMessage = false;
12133  Train.ZeroPowerNoJoinedByMessage = false;
12134  Train.ZeroPowerNoCDTMessage = false;
12135  Train.ZeroPowerNoNewServiceMessage = false;
12137  Train.ZeroPowerNoRepeatShuttleMessage = false;
12139  Utilities->CallLogPop(2159);
12140  }
12141  catch(const Exception &e)
12142  {
12143  ErrorLog(208, e.Message);
12144  }
12145 }
12146 
12147 // ---------------------------------------------------------------------------
12148 
12149 void __fastcall TInterface::SkipTimetabledActionsMenuItemClick(TObject *Sender)
12150 {
12151 /* Only enable this for stopped at signal or stopped at location.
12152 
12153 If stopped at signal then next action will be TimeLoc arrival, TimeTimeLoc, Pass or Fer.
12154 
12155 If stopped at a location then next action will be TimeTimeLoc dep/TimeLoc dep/jbo/fsp/rsp/cdt/Frh/Fns/Fjo/Frh-sh/Fns-sh/F-nshs.
12156 
12157 FormatType: NoFormat, TimeLoc, TimeTimeLoc, TimeCmd, StartNew, TimeCmdHeadCode, FinRemHere, FNSNonRepeatToShuttle, SNTShuttle, SNSShuttle,
12158 SNSNonRepeatFromShuttle, FSHNewService, Repeat, PassTime, ExitRailway
12159 
12160 SequenceType: NoSequence, Start, Finish, Intermediate, SequTypeForRepeatEntry
12161 */
12162  try
12163  {
12164  TrainController->LogEvent("SkipTimetabledActionsMenuItemClick");
12165  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SkipTimetabledActionsMenuItemClick");
12166  TTrain Train = TrainController->TrainVectorAtIdent(55, SelectedTrainID); //Train not modified here so don't need reference
12167  SkipTTActionsListBox->Clear();
12168  SkipTTActionsListBox->ExtendedSelect = false; //this and the next allow only one item to be selected
12169  SkipTTActionsListBox->MultiSelect = false;
12170 
12171  //populate the listbox
12172  AnsiString TTStr = Train.FloatingTimetableString(2, Train.ActionVectorEntryPtr);
12173  AnsiString OneLine;
12174  int Count = 0;
12175  int NewLinePos = TTStr.Pos('\n');
12176  SkipTTActionsListBox->Width = 200;
12177  SkipListHeaderPanel->Width = 200;
12178  for(int x = 0; x < 30; x++)
12179  {
12180  if((TTStr.Length() > 1) && (NewLinePos <= TTStr.Length()) && (NewLinePos != 0)) //i.e. all lines apart from the last where there is no newline
12181  {
12182  OneLine = TTStr.SubString(1, NewLinePos);
12183  if(OneLine == "")
12184  {
12185  break; //break before Count increment
12186  }
12187  Count++;
12188  SkipTTActionsListBox->Items->Add(OneLine);
12189  TTStr = TTStr.SubString(NewLinePos + 1, TTStr.Length() - NewLinePos - 1);
12190  NewLinePos = TTStr.Pos('\n');
12191  }
12192  else if((TTStr.Length() > 1) && (NewLinePos == 0) && ((TTStr.SubString(3, 1) == ':') || (TTStr.SubString(1, 5) == "Termi"))) //last line
12193  {
12194  OneLine = TTStr;
12195  Count++;
12196  SkipTTActionsListBox->Items->Add(OneLine);
12197  break;
12198  }
12199  if(TTStr.Length() <2)
12200  {
12201  break;
12202  }
12203  AnsiString EndStr = OneLine.SubString(8, 5);
12204  //need these last checks in case last floating line is an allowable exit or a new service departure time which aren't wanted in the skip list
12205  if((EndStr == "Form ") || (EndStr == "Join ") || (EndStr == "Exit ")) //all these are preceded by a time & start at character 8
12206  {
12207  break;
12208  }
12209  }
12210  if(Count == 0)
12211  {
12212  ShowMessage("No timetabled events");
12213  Utilities->CallLogPop(2428);
12214  return;
12215  }
12216  SkipTTActionsListBox->Height = (SkipTTActionsListBox->ItemHeight * Count) + 4;
12217 //position listbox
12218  int Left = SkipTTTrainMousePosX + MainScreen->Left + 16; // so lhs of window is WindowOffset to the right of the mouse pos
12219  if((Left + SkipTTActionsListBox->Width) > MainScreen->Left + MainScreen->Width)
12220  {
12221  Left = SkipTTTrainMousePosX - SkipTTActionsListBox->Width + 16;
12222  }
12223  int Top = SkipTTTrainMousePosY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
12224  if((Top + SkipTTActionsListBox->Height) > MainScreen->Top + MainScreen->Height)
12225  {
12226  Top = SkipTTTrainMousePosY - SkipTTActionsListBox->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
12227  if(Top < 30)
12228  {
12229  Top = 30;
12230  }
12231  }
12232  SkipTTActionsListBox->Left = Left; // new at v2.7.0 in place of above
12233  SkipListHeaderPanel->Left = Left;
12234  SkipTTActionsListBox->Top = Top;
12235  SkipListHeaderPanel->Top = Top - 34; //this panel has a height of 34
12237  Utilities->CallLogPop(2418);
12238  }
12239  catch(const Exception &e)
12240  {
12241  ErrorLog(241, e.Message);
12242  }
12243 }
12244 
12245 //---------------------------------------------------------------------------
12246 
12247 void __fastcall TInterface::SkipTTActionsListBoxMouseUp(TObject *Sender, TMouseButton Button,
12248  TShiftState Shift, int X, int Y)
12249 /*
12250 If stopped at signal then allowable next action will be TimeLoc arrival, TimeTimeLoc, Pass or Fer.
12251 
12252 If stopped at a location then save the depart time then allowable next action will be TimeLoc arrival, TimeTimeLoc, Pass or Fer.
12253 
12254 FormatType: NoFormat, TimeLoc, TimeTimeLoc, TimeCmd, StartNew, TimeCmdHeadCode, FinRemHere, FNSNonRepeatToShuttle, SNTShuttle, SNSShuttle,
12255 SNSNonRepeatFromShuttle, FSHNewService, Repeat, PassTime, ExitRailway
12256 
12257 SequenceType: NoSequence, Start, Finish, Intermediate, SequTypeForRepeatEntry
12258 */
12259 {
12260  try
12261  {
12262  TrainController->LogEvent("SkipTTActionsListBoxMouseUp, " + AnsiString(X) + ',' + AnsiString(Y));
12263  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SkipTTActionsListBoxMouseUp");
12264  TTrain &Train = TrainController->TrainVectorAtIdent(56, SelectedTrainID); //Train actionvectorptr advance here so need reference
12265  Train.SkipPtrValue = 0;
12266  if(SkipTTActionsListBox->Items->Text != "") //not empty
12267  {
12268  Train.SelSkipString = SkipTTActionsListBox->Items->Strings[SkipTTActionsListBox->ItemIndex]; //index starts at 0
12269  }
12270  if(Train.StoppedAtSignal)
12271  {
12272  //Calc cumulative dwell times that are skipped
12273  int Count = 0, PassNum = 0, SkippedEvents = 0;
12274  if(SkipTTActionsListBox->ItemIndex == 0)
12275  {
12276  ShowMessage("This is already the next event, nothing will be skipped");
12277  Utilities->CallLogPop(2436);
12278  return;
12279  }
12280  for(TActionVectorEntry *AVEPtr = Train.ActionVectorEntryPtr; Count < SkipTTActionsListBox->ItemIndex; AVEPtr++)
12281  {
12282  if((AVEPtr->FormatType == TimeTimeLoc) && (AVEPtr->ArrivalTime != AVEPtr->DepartureTime))
12283  {//arr & dep in a single AVEntry if different arr & dep times but two listings, if have same arr & dep time then only a single listing,
12284  Count += 2;
12285  }
12286  else
12287  {
12288  Count++;
12289  }
12290  PassNum++;
12291  if((AVEPtr->Command == "cdt") || (AVEPtr->Command == "pas") || ((AVEPtr->FormatType == TimeLoc) && (AVEPtr->DepartureTime != TDateTime(-1))))
12292  //don't count cdts, passes or departures as missed events (note that can't be a finish)
12293  {
12294  continue;
12295  }
12296  else
12297  {
12298  SkippedEvents++;
12299  }
12300  }
12301  AnsiString StartStr = Train.SelSkipString.SubString(8, 4);
12302  if((StartStr != "Arri") && (StartStr != "Pass") && (StartStr != "Exit"))
12303  {
12304  ShowMessage("When stopped at a signal the selected next event must be 'Arrive...', 'Pass...', or 'Exit railway...'");
12305  Utilities->CallLogPop(2429);
12306  return;
12307  }
12308  //advance the pointer but ask for confirmation first
12309  int button = Application->MessageBox(L"This will skip all events before the selection,\n\nOK to proceed?", L"", MB_YESNO);
12310  if(button == IDYES)
12311  {
12312  AnsiString SkipTTLBString = AnsiString(SkipTTActionsListBox->Items->Strings[SkipTTActionsListBox->ItemIndex]); //added at v2.12.0 as doubt over newline in ListBox strings
12313  if(SkipTTLBString[SkipTTLBString.Length()] == '\n') //strip the newline if there is one as one is added after PerfStr sent to PerformanceFile
12314  {
12315  SkipTTLBString = SkipTTLBString.SubString(1, (SkipTTLBString.Length() - 1));
12316  }
12317  Train.ActionVectorEntryPtr += PassNum;
12318  AnsiString PerfStr = Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": " + Train.HeadCode + " " + AnsiString(SkippedEvents)
12319  + " timetabled events skipped until " + SkipTTLBString;
12320  Utilities->PerformanceFile << PerfStr.c_str() << '\n';
12321  Utilities->PerformanceFile.flush(); //added at v2.13.0
12322  TrainController->SkippedTTEvents += SkippedEvents;
12323  Display->PerformanceMemo->Lines->Add(PerfStr);
12324 
12325  }
12327  }
12328  else if(Train.RevisedStoppedAtLoc())
12329  {
12330  //Calc cumulative dwell times that are skipped
12331  int Count = 0, PassNum = 0, SkippedEvents = 0;
12332  TActionVectorEntry DepEntry;
12333  Train.SkippedDeparture = false;
12334  if(SkipTTActionsListBox->ItemIndex == 0)
12335  {
12336  ShowMessage("This is already the next event, nothing will be skipped");
12337  Utilities->CallLogPop(2437);
12338  return;
12339  }
12340  for(TActionVectorEntry *AVEPtr = Train.ActionVectorEntryPtr; Count < SkipTTActionsListBox->ItemIndex; AVEPtr++) //Count < rather than == because incremented at end
12341  {
12342  if(AVEPtr->DepartureTime > TDateTime(0)) //departure action
12343  {
12344  if(AVEPtr->LocationName == Train.ActionVectorEntryPtr->LocationName)
12345  {
12346  Train.SkippedDeparture = true;
12347  }
12348  }
12349  if((AVEPtr->FormatType == TimeTimeLoc) && (AVEPtr->ArrivalTime != AVEPtr->DepartureTime) && (AVEPtr != Train.ActionVectorEntryPtr))
12350  {//arr & dep in a single AVEntry if different arr & dep times but two listings, if have same arr & dep time then only a single listing,
12351  //if first entry is a TimeTimeLoc departure then only one listing
12352  Count += 2;
12353  }
12354  else
12355  {
12356  Count++;
12357  }
12358  PassNum++;
12359  if((AVEPtr->Command == "cdt") || (AVEPtr->Command == "pas") || ((AVEPtr->FormatType == TimeLoc) && (AVEPtr->DepartureTime > TDateTime(0))))
12360  //don't count cdts, passes or departures as missed events (note that can't be a finish)
12361  {
12362  continue;
12363  }
12364  else
12365  {
12366  SkippedEvents++;
12367  }
12368  }
12369  TActionVectorEntry *AVEPtr = Train.ActionVectorEntryPtr + PassNum; //set to the selected action so can check if at same location
12370  Train.TrainSkippedEvents = SkippedEvents;
12371  AnsiString StartStr = Train.SelSkipString.SubString(8, 4);
12372  if(Train.SkippedDeparture && (AVEPtr->LocationName == Train.ActionVectorEntryPtr->LocationName) && (AVEPtr->ArrivalTime == TDateTime(-1)) && (AVEPtr->FormatType != PassTime))
12373  { //if selected action is at same location and SkippedDeparture is true (i.e returned to it after leaving), then keep SkippedDep provided that the action is arrive or pass
12374  Train.SkippedDeparture = false;
12375  }
12376  if((StartStr != "Arri") && (StartStr != "Pass") && (StartStr != "Exit") && (AVEPtr->LocationName != Train.ActionVectorEntryPtr->LocationName))
12377  {
12378  ShowMessage("When stopped at a location the selected next event must either occur at the same location or be 'Arrive...', 'Pass...', or 'Exit railway...'");
12379  Train.SkippedDeparture = false;
12380  Train.SkipPtrValue = 0;
12381  Utilities->CallLogPop(2435);
12382  return;
12383  }
12384  if(Train.SkippedDeparture)
12385  {
12386  Train.SkipPtrValue = AVEPtr - &(Train.TrainDataEntryPtr->ActionVector.at(0)); //i.e. ActionVectorEntryPtr value above start
12387  } //can't save pointer itself as will be stored in a session file
12388  //advance the pointer but ask for confirmation first
12389  UnicodeString Message = "This will skip all events before the selection.\n\nOK to proceed?";
12390  if(Train.SkippedDeparture)
12391  {
12392  Message = "This will skip all events between the departure and the selection.\n\n"
12393  "Note that no more events may be skipped for this train until after\n"
12394  "it departs from the current location\n\nOK to proceed?";
12395  }
12396  int button = Application->MessageBox(Message.c_str(), L"", MB_YESNO);
12397  if(button == IDYES)
12398  {
12399  AnsiString SkipTTLBString = AnsiString(SkipTTActionsListBox->Items->Strings[SkipTTActionsListBox->ItemIndex]); //added at v2.12.0 as doubt over newline in
12400  //ListBox strings, mainly there is one but seemingly not always
12401  if(SkipTTLBString[SkipTTLBString.Length()] == '\n') //strip the newline if there is one as one is added after PerfStr sent to PerformanceFile
12402  {
12403  SkipTTLBString = SkipTTLBString.SubString(1, (SkipTTLBString.Length() - 1));
12404  }
12405  if(!Train.SkippedDeparture)
12406  {
12407  Train.ActionVectorEntryPtr += PassNum; //points to the next action, if a dep is skipped then the pointer is incremented later
12408  AnsiString PerfStr = Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": " + Train.HeadCode + " timetabled events skipped until " +
12409  SkipTTLBString;
12411  Train.TrainSkippedEvents = 0;
12412  Utilities->PerformanceFile << PerfStr.c_str() << '\n';
12413  Utilities->PerformanceFile.flush(); //added at v2.13.0
12414  Display->PerformanceMemo->Lines->Add(PerfStr);
12415  }
12416  else
12417  {
12418  Train.ActionsSkippedFlag = true; //set to prevent any further skips until after the departure
12419  AnsiString PerfStr = Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": " + Train.HeadCode + " " + AnsiString(Train.TrainSkippedEvents)
12420  + " timetabled events skipped after the departure until " + SkipTTLBString;
12421  Utilities->PerformanceFile << PerfStr.c_str() << '\n';
12422  Utilities->PerformanceFile.flush(); //added at v2.13.0
12423  Display->PerformanceMemo->Lines->Add(PerfStr);
12424  }
12425  }
12426  else
12427  {
12428  Train.SkippedDeparture = false;
12429  Train.SkipPtrValue = 0;
12430  Train.ActionsSkippedFlag = false;
12431  }
12433  }
12434  Utilities->CallLogPop(2427);
12435  }
12436  catch(const Exception &e)
12437  {
12438  ErrorLog(242, e.Message);
12439  }
12440 }
12441 
12442 //---------------------------------------------------------------------------
12443 
12444 void TInterface::ShowTTActionsListBox(int Caller) //TTClock stopped in ClockTimer2
12445 {
12446  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowTTActionsListBox");
12447  if(SkipTTActionsListBox->Visible)
12448  {
12449  Utilities->CallLogPop(2430);
12450  return;
12451  }
12452  SkipTTActionsListBox->Visible = true;
12453  SkipListHeaderPanel->Visible = true;
12454  SkipTTActionsListBox->BringToFront();
12455  SkipListHeaderPanel->BringToFront();
12456  Utilities->CallLogPop(2431);
12457 }
12458 
12459 //---------------------------------------------------------------------------
12460 
12462 {
12463  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HideTTActionsListBox");
12464  if(!SkipTTActionsListBox->Visible)
12465  {
12466  Utilities->CallLogPop(2432);
12467  return;
12468  }
12469  SkipTTActionsListBox->Visible = false;
12470  SkipListHeaderPanel->Visible = false;
12471  Utilities->CallLogPop(2433);
12472 }
12473 
12474 //---------------------------------------------------------------------------
12475 
12476 void __fastcall TInterface::SkipListExitImageClick(TObject *Sender)
12477 {
12478  try
12479  {
12480  TrainController->LogEvent("SkipListExitImageClick");
12481  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SkipListExitImageClick");
12483  Utilities->CallLogPop(2434);
12484  }
12485  catch(const Exception &e)
12486  {
12487  ErrorLog(243, e.Message);
12488  }
12489 }
12490 
12491 //---------------------------------------------------------------------------
12492 
12493 void __fastcall TInterface::BecomeNewServiceMenuItemClick(TObject *Sender) //added at v2.12.0
12494 {
12495  //this is only accessible if the train is stopped at a location, there is a follow-on service (Fns, Fns-sh, Frh-sh, F-nshs) and that service stops at or passes the current
12496  // location. Change to new service immediately & set its ActionVectorEntryPtr to this location
12497  try
12498  {
12499  TrainController->LogEvent("BecomeNewServiceClick");
12500  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BecomeNewServiceClick");
12502  TActionVectorEntry *NewServiceActionEntryPtr = Train.ActionVectorEntryPtr; //set initially to current position
12503  while((NewServiceActionEntryPtr->Command != "Fns") && (NewServiceActionEntryPtr->Command != "Fns-sh") && (NewServiceActionEntryPtr->Command != "F-nshs"))
12504  {
12505  NewServiceActionEntryPtr++;
12506  if(NewServiceActionEntryPtr > &Train.TrainDataEntryPtr->ActionVector.back()) //failed to find a new service
12507  {
12508  ShowMessage("No follow-on service found, option unavailable");
12509  Utilities->CallLogPop(2445);
12510  return;
12511  }
12512  }
12513  int PtrAdvance = NewServiceActionEntryPtr - Train.ActionVectorEntryPtr;
12514  AnsiString CurrentLocationName = Train.ActionVectorEntryPtr->LocationName;
12515  UnicodeString MessageStr = "This action will skip all timetabled events until follow-on service " + Train.FollowOnServiceRef + " reaches this location\n\nOK to proceed?";
12516  if(NewServiceActionEntryPtr->Command == "Fns")
12517  {
12518  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
12520  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
12521  TrainController->BaseTime = TDateTime::CurrentDateTime();
12523  if(button == IDNO)
12524  {
12525  Train.FollowOnServiceRef = ""; //cancel this as finished with it
12526  Utilities->CallLogPop(2446);
12527  return;
12528  }
12530  Train.NewTrainService(1, true); //true for no logs
12531  }
12532  else if(NewServiceActionEntryPtr->Command == "Fns-sh")
12533  {
12534  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
12536  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
12537  TrainController->BaseTime = TDateTime::CurrentDateTime();
12539  if(button == IDNO)
12540  {
12541  Train.FollowOnServiceRef = ""; //cancel this as finished with it
12542  Utilities->CallLogPop(2447);
12543  return;
12544  }
12546  Train.RepeatShuttleOrNewNonRepeatService(1, true); //true for no logs
12547  }
12548  else if(NewServiceActionEntryPtr->Command == "Frh-sh")
12549  {
12550  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
12552  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
12553  TrainController->BaseTime = TDateTime::CurrentDateTime();
12555  if(button == IDNO)
12556  {
12557  Train.FollowOnServiceRef = ""; //cancel this as finished with it
12558  Utilities->CallLogPop(2453);
12559  return;
12560  }
12562  Train.RepeatShuttleOrRemainHere(1, true); //true for no logs;
12563  }
12564  else if(NewServiceActionEntryPtr->Command == "F-nshs")
12565  {
12566  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
12568  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
12569  TrainController->BaseTime = TDateTime::CurrentDateTime();
12571  if(button == IDNO)
12572  {
12573  Train.FollowOnServiceRef = ""; //cancel this as finished with it
12574  Utilities->CallLogPop(2448);
12575  return;
12576  }
12578  Train.NewShuttleFromNonRepeatService(1, true); //true for no logs;
12579  }
12580  else //invalid, shouldn't have been possible to select it
12581  {
12582  ShowMessage("Option unavailable");
12583  }
12584 
12585  SkipEventsBeforeSameLoc(0, SelectedTrainID, CurrentLocationName); //same train ID when becomes new service
12586  Train.DepartureTimeSet = false; //force a release time calculation in UpdateTrain
12587  Train.EntrySpeed = 0;
12588  Train.ExitSpeedHalf = 0;
12589  Train.ExitSpeedFull = 0;
12590  if(Train.ActionVectorEntryPtr->Command == "pas")
12591  {
12592  Train.StoppedAtLocation = false; //this is set in the functions called for the various finish types, so is reset here in the case of a pass
12593  Train.ExitSpeedHalf = 30; //so earlier versions will still identify it as moving. exit speed will be recalculated for v2.12.0 & upwards
12594  Train.ExitSpeedFull = 50;
12595  }
12596  Train.FollowOnServiceRef = ""; //cancel this as finished with it
12597  Utilities->CallLogPop(2449);
12598  }
12599  catch(const Exception &e)
12600  {
12601  ErrorLog(244, e.Message);
12602  }
12603 }
12604 
12605 //---------------------------------------------------------------------------
12606 
12607 bool TInterface::IsBecomeNewServiceAvailable(int Caller, int TrainID, AnsiString &NextServiceRef)
12608 {// 5 conditions: stopped at location, has power, no skipped departure pending, has follow-on service (Fns, Fns-sh, Frh-sh, F-nshs) and follow-on service stops at or passes this location
12609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", BecomeNewServiceAvailable, " + AnsiString(TrainID));
12611  bool Condition4Met = false;
12612  TTrainDataEntry *NextServiceEntryPtr;
12613  NextServiceRef = "";
12614  if(Train.RevisedStoppedAtLoc() && (Train.PowerAtRail > 1) && !Train.SkippedDeparture) //conditions 1 to 3
12615  {
12616  for(TActionVectorEntry *AVEPtr = Train.ActionVectorEntryPtr; AVEPtr <= &Train.TrainDataEntryPtr->ActionVector.back(); AVEPtr++)
12617  {
12618  if(AVEPtr->Command == "Fns")
12619  {
12620  Condition4Met = true;
12621  NextServiceEntryPtr = AVEPtr->LinkedTrainEntryPtr;
12622  NextServiceRef = NextServiceEntryPtr->ServiceReference;
12623  break;
12624  }
12625  if(AVEPtr->Command == "Fns-sh")
12626  {
12627  Condition4Met = true;
12628  if(Train.RepeatNumber >= (Train.TrainDataEntryPtr->NumberOfTrains - 1)) // finished all repeats
12629  {
12630  NextServiceEntryPtr = AVEPtr->NonRepeatingShuttleLinkEntryPtr;
12631  NextServiceRef = NextServiceEntryPtr->ServiceReference;
12632  }
12633  else
12634  {
12635  NextServiceEntryPtr = AVEPtr->LinkedTrainEntryPtr;
12636  NextServiceRef = NextServiceEntryPtr->ServiceReference;
12637  }
12638  break;
12639  }
12640  if(AVEPtr->Command == "Frh-sh")
12641  {
12642  if(Train.RepeatNumber >= (Train.TrainDataEntryPtr->NumberOfTrains - 1)) // finished all repeats
12643  {
12644  break; //no follow-on service
12645  }
12646  else
12647  {
12648  Condition4Met = true;
12649  NextServiceEntryPtr = AVEPtr->LinkedTrainEntryPtr;
12650  NextServiceRef = NextServiceEntryPtr->ServiceReference;
12651  break;
12652  }
12653  }
12654  if(AVEPtr->Command == "F-nshs")
12655  {
12656  Condition4Met = true;
12657  NextServiceEntryPtr = AVEPtr->LinkedTrainEntryPtr;
12658  NextServiceRef = NextServiceEntryPtr->ServiceReference;
12659  break;
12660  }
12661  }
12662  if(Condition4Met) //condition 4
12663  {
12664  AnsiString CurLoc = Train.ActionVectorEntryPtr->LocationName;
12665  for(TActionVectorEntry *AVEPtr = &NextServiceEntryPtr->ActionVector.at(0); AVEPtr <= &NextServiceEntryPtr->ActionVector.back(); AVEPtr++)
12666  {
12667  if(AVEPtr->LocationName == CurLoc)
12668  {
12669  if((AVEPtr->FormatType == TimeTimeLoc) || ((AVEPtr->FormatType == TimeLoc) && (AVEPtr->ArrivalTime > TDateTime(0))) || (AVEPtr->Command == "pas") )
12670  {
12671  Utilities->CallLogPop(2454);
12672  return(true); //all conditions met
12673  }
12674  }
12675  }
12676  }
12677  }
12678  Utilities->CallLogPop(2455);
12679  return(false); //one or more conditions not met
12680 }
12681 
12682 //---------------------------------------------------------------------------
12683 
12684 void TInterface::SkipAllEventsBeforeNewService(int Caller, int TrainID, int PtrAdvance) //added at v2.12.0
12685 {
12686  try
12687  {
12688  TrainController->LogEvent("SkipAllEventsBeforNewService");
12689  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", SkipAllEventsBeforNewService");
12690  TTrain &Train = TrainController->TrainVectorAtIdent(59, TrainID);
12691  TActionVectorEntry *NewServiceActionEntryPtr = Train.ActionVectorEntryPtr + PtrAdvance;
12692  //Calc no. of skipped events
12693  int SkippedEvents = 0;
12694  for(TActionVectorEntry *AVEPtr = Train.ActionVectorEntryPtr; AVEPtr < NewServiceActionEntryPtr; AVEPtr++)
12695  {
12696  if((AVEPtr->Command == "cdt") || (AVEPtr->Command == "pas") || (AVEPtr->SequenceType == Finish) ||
12697  ((AVEPtr->FormatType == TimeLoc) && (AVEPtr->DepartureTime != TDateTime(-1))))
12698  //don't count cdts, passes, finishes or departures as missed events (finish will be the new service and becomes new service at diff loc so it isn't missed)
12699  {
12700  continue;
12701  }
12702  else
12703  {
12704  SkippedEvents++;
12705  }
12706  }
12707  //report the action
12708  AnsiString PerfStr = Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": " + Train.HeadCode + " manually advanced to follow-on service " + Train.FollowOnServiceRef + " at " +
12710  Utilities->PerformanceFile << PerfStr.c_str() << '\n';
12711  Utilities->PerformanceFile.flush(); //added at v2.13.0
12712  Display->PerformanceMemo->Lines->Add(PerfStr);
12713  //advance the pointer
12714  Train.ActionVectorEntryPtr = NewServiceActionEntryPtr; //points to the new service
12715  PerfStr = Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": " + Train.HeadCode + " " + AnsiString(SkippedEvents)
12716  + " timetabled events skipped before it became the new service";
12717  TrainController->SkippedTTEvents += SkippedEvents;
12718  Utilities->PerformanceFile << PerfStr.c_str() << '\n';
12719  Utilities->PerformanceFile.flush(); //added at v2.13.0
12720  Display->PerformanceMemo->Lines->Add(PerfStr);
12721  Utilities->CallLogPop(2450);
12722  return;
12723  }
12724  catch(const Exception &e)
12725  {
12726  ErrorLog(245, e.Message);
12727  }
12728 }
12729 
12730 //---------------------------------------------------------------------------
12731 
12732 void TInterface::SkipEventsBeforeSameLoc(int Caller, int TrainID, AnsiString LocationName) //added at v2.12.0
12733 {
12734  try
12735  {
12736  TrainController->LogEvent("SkipEventsBeforeSameLoc");
12737  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", SkipEventsBeforeSameLoc");
12738  TTrain &Train = TrainController->TrainVectorAtIdent(60, TrainID);
12739  bool LocFound = false;
12740  //Calc no. of skipped events
12741  int SkippedEvents = 0;
12742  TActionVectorEntry *AVEPtr;
12743  for(AVEPtr = Train.ActionVectorEntryPtr; AVEPtr <= &Train.TrainDataEntryPtr->ActionVector.back(); AVEPtr++)
12744  {
12745  if(AVEPtr->LocationName != LocationName)
12746  {
12747  if((AVEPtr->Command == "cdt") || (AVEPtr->Command == "pas") || ((AVEPtr->FormatType == TimeLoc) && (AVEPtr->DepartureTime != TDateTime(-1))))
12748  //don't count cdts, passes or departures as missed events (can't be a finish)
12749  {
12750  continue;
12751  }
12752  else
12753  {
12754  SkippedEvents++;
12755  }
12756  }
12757  else if(AVEPtr->FormatType == TimeTimeLoc)
12758  {
12759  LocFound = true;
12760  break;
12761  }
12762  else if(AVEPtr->Command == "pas")
12763  {
12764  Train.TreatPassAsTimeLocDeparture = true; //when true the pas is treated by the train as a TimeLoc departure
12765  LocFound = true;
12766  break;
12767  }
12768  else if(((AVEPtr->FormatType == TimeLoc) && (AVEPtr->ArrivalTime > TDateTime(-1))) || (AVEPtr->Command == "cdt")) //increment past arrival & cdt events
12769  { //no skipped event as stops here
12770  continue;
12771  }
12772  else
12773  {
12774  LocFound = true;
12775  break;
12776  }
12777  }
12778  if(!LocFound)
12779  {
12780  Utilities->CallLogPop(2451);
12781  ShowMessage("New service location not found");
12782  return;
12783  }
12784  //advance the pointer
12785  Train.ActionVectorEntryPtr = AVEPtr;
12786  Train.ChangeTrainDirection(1, true); //most times this will be appropriate, i.e changed direction from other service train, true for No Logs
12787  AnsiString PerfStr = Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": " + Train.HeadCode + " " + AnsiString(SkippedEvents)
12788  + " timetabled events skipped before the new service arrived at " + LocationName;
12789  TrainController->SkippedTTEvents += SkippedEvents;
12790  Utilities->PerformanceFile << PerfStr.c_str() << '\n';
12791  Utilities->PerformanceFile.flush(); //added at v2.13.0
12792  Display->PerformanceMemo->Lines->Add(PerfStr);
12793  Utilities->CallLogPop(2452);
12794  return;
12795  }
12796  catch(const Exception &e)
12797  {
12798  ErrorLog(246, e.Message);
12799  }
12800 }
12801 
12802 //---------------------------------------------------------------------------
12803 
12804 void __fastcall TInterface::SignallerControlStopMenuItemClick(TObject *Sender)
12805 {
12806  try
12807  {
12808  TrainController->LogEvent("SignallerControlStopMenuItemClick");
12809  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControlStopMenuItemClick");
12812  if(Train.LeadElement > -1)
12813  {
12814  if(Track->TrackElementAt(787, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
12815  {
12816  Train.SignallerStoppingFlag = true;
12817  Train.SignallerStopBrakeRate = 0;
12818  Train.LogAction(24, Train.HeadCode, "", SignallerControlStop, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
12819  }
12820  else
12821  {
12823  }
12824  }
12825  else
12826  {
12828  }
12829  Utilities->CallLogPop(1553);
12830  }
12831  catch(const Exception &e)
12832  {
12833  ErrorLog(161, e.Message);
12834  }
12835 }
12836 
12837 // ---------------------------------------------------------------------------
12838 void __fastcall TInterface::PassRedSignalMenuItemClick(TObject *Sender)
12839 {
12840  try
12841  {
12842  TrainController->LogEvent("PassRedSignalMenuItemClick");
12843  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PassRedSignalMenuItemClick");
12845  Train.SignallerStoppingFlag = false;
12846  int NextElementPos = Track->TrackElementAt(712, Train.LeadElement).Conn[Train.LeadExitPos];
12847  if(NextElementPos < 0)
12848  {
12849  throw Exception("Error, no element in front in PassRedSignalMenuItemClick");
12850  }
12851  TTrackElement &TrackElement = Track->TrackElementAt(653, NextElementPos);
12852 /* drop this error as may be some circumstances where behind a signal in sig mode but not stopped at signal
12853  if(!Train.StoppedAtSignal)
12854  {
12855  throw Exception("Error, not StoppedAtSignal in PassRedSignalMenuItemClick");
12856  }
12857 */
12858  if(TrackElement.TrackType != SignalPost)
12859  {
12860  throw Exception("Error, next element not a signal type in PassRedSignalMenuItemClick");
12861  }
12862  Train.SignallerStopped = false;
12863  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
12864  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
12865  // since no need to alert the user
12866  Train.StoppedAfterSPAD = false; // in case had been set
12867  Train.SPADFlag = false;
12868  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
12870  Train.AllowedToPassRedSignal = true;
12871  Train.LogAction(4, Train.HeadCode, "", SignallerPassRedSignal, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
12872  Utilities->CallLogPop(1199);
12873  }
12874  catch(const Exception &e)
12875  {
12876  ErrorLog(162, e.Message);
12877  }
12878 }
12879 // ---------------------------------------------------------------------------
12880 
12881 void __fastcall TInterface::StepForwardMenuItemClick(TObject *Sender)
12882 {
12883  try
12884  {
12885  TrainController->LogEvent("StepForwardMenuItemClick");
12886  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",StepForwardMenuItemClick");
12888  Train.SignallerStoppingFlag = false;
12889  Train.SignallerStopped = false;
12890  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
12891  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
12892  // since no need to alert the user
12893  Train.StoppedAfterSPAD = false; // in case had been set
12894  Train.SPADFlag = false;
12895  Train.StepForwardFlag = true;
12896  Train.AllowedToPassRedSignal = true; // in case at a signal, will clear when half-way into next element whether a signal or not
12897  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
12899  Train.LogAction(32, Train.HeadCode, "", SignallerStepForward, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
12900  int NextElementPos = -1;
12901 // addition for v1.3.2 due to Carwyn Thomas error: can't select StepForwardMenuItem if exiting at a continuation but leave this in anyway
12902  int NextEntryPos = -1; // ---ditto---
12903  if(Train.LeadElement > -1) // ---ditto---
12904  {
12905  // ---ditto---
12906  NextElementPos = Track->TrackElementAt(804, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
12907  NextEntryPos = Track->TrackElementAt(805, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
12908  } // ---ditto---
12909 
12910  if((NextElementPos > -1) && (NextEntryPos > -1))
12911  {
12912  // call this after StepForwardFlag set
12913  Train.EntrySpeed = 0;
12915  Train.FirstHalfMove = true;
12916  Train.SetTrainMovementValues(20, NextElementPos, NextEntryPos); // NextElement is the element to be entered
12917  }
12918  Utilities->CallLogPop(1800);
12919  }
12920  catch(const Exception &e)
12921  {
12922  ErrorLog(163, e.Message);
12923  }
12924 }
12925 
12926 // ---------------------------------------------------------------------------
12927 
12928 void __fastcall TInterface::RemoveTrainMenuItemClick(TObject *Sender)
12929 {
12930  try
12931  {
12932  TrainController->LogEvent("RemoveTrainMenuItemClick");
12933  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemoveTrainMenuItemClick");
12935  if((!Train.Derailed) && (!Train.Crashed))
12936  {
12937  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
12939  UnicodeString Message = UnicodeString(Train.HeadCode) + " will be removed from the railway - proceed?";
12940  int button = Application->MessageBox(Message.c_str(), L"Please confirm", MB_YESNO);
12941  TrainController->BaseTime = TDateTime::CurrentDateTime();
12943  if(button == IDNO)
12944  {
12945  Utilities->CallLogPop(1801);
12946  return;
12947  }
12948  }
12949  Train.SignallerStoppingFlag = false;
12950  Train.TrainGone = true; // will be removed by TTrainController::Operate
12951  Train.SignallerRemoved = true;
12952  Train.TrainDataEntryPtr->TrainOperatingDataVector.at(Train.RepeatNumber).RunningEntry = Exited;
12953  AnsiString LocName = "";
12954  if(Train.LeadElement > -1)
12955  {
12956  LocName = Track->TrackElementAt(641, Train.LeadElement).ActiveTrackElementName;
12957  }
12958  if((LocName == "") && (Train.MidElement > -1))
12959  {
12960  LocName = Track->TrackElementAt(642, Train.MidElement).ActiveTrackElementName;
12961  }
12962  if((LocName == "") && Train.LeadElement > -1)
12963  {
12964  LocName = Track->TrackElementAt(643, Train.LeadElement).ElementID;
12965  }
12966  if((LocName == "") && (Train.MidElement > -1))
12967  {
12968  LocName = Track->TrackElementAt(644, Train.MidElement).ElementID;
12969  }
12970  TTrackElement *TrackElementPtr;
12971  int RouteNumber;
12972  TAllRoutes::TRouteType RouteType;
12973  if(Train.LeadElement > -1)
12974  {
12975  TrackElementPtr = &(Track->TrackElementAt(673, Train.LeadElement));
12976  // remove TrainIDs from track element, added at v2.4.0
12977  if(TrackElementPtr->TrackType == Bridge)
12978  {
12979  if(Train.LeadExitPos > 1)
12980  {
12981  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
12982  }
12983  else
12984  {
12985  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
12986  }
12987  }
12988  else
12989  {
12990  TrackElementPtr->TrainIDOnElement = -1;
12991  }
12992  // reset any CallingOnSet flags for signals, if facing wrong way doesn't matter, shouldn't be set anyay
12993  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
12994  {
12995  TrackElementPtr->CallingOnSet = false;
12996  Track->PlotSignal(6, *TrackElementPtr, Display);
12997  }
12998 // [added at v1.3.0] here check if on an automatic signals route and if so reset signals for the entire route from the
12999 // start of the route - after the train has been removed, use LeadElement and also MidElement (if no autosigs route at LeadElement) just to be sure
13000  RouteType = AllRoutes->GetRouteTypeAndNumber(27, Train.LeadElement, Train.LeadEntryPos, RouteNumber);
13001  if(RouteType == TAllRoutes::AutoSigsRoute)
13002  {
13005  }
13006 // end of addition
13007 
13008 // erase a stub route if there is one, added at v2.6.1
13009 // first element of route is immediately in front of the train
13010  if(Train.LeadExitPos >= 0)
13011  {
13012  TTrackElement LeadTrackElement = Track->TrackElementAt(1013, Train.LeadElement);
13013  int FirstRouteElementVecPos = LeadTrackElement.Conn[Train.LeadExitPos];
13014  int FirstRouteLinkPos = LeadTrackElement.ConnLinkPos[Train.LeadExitPos];
13015  RouteType = AllRoutes->GetRouteTypeAndNumber(39, FirstRouteElementVecPos, FirstRouteLinkPos, RouteNumber);
13016  if(RouteType == TAllRoutes::NotAutoSigsRoute) // red or green route, if no route then ignore
13017  {
13018  TOneRoute &OR = AllRoutes->GetModifiableRouteAt(30, RouteNumber);
13019  TTrackElement TE = Track->TrackElementAt(1014, FirstRouteElementVecPos);
13020  if((TE.TrackType != SignalPost) && (TE.TrackType != Continuation))
13021  // all autosigs routes have signalpost or continuation at 0 so they are automatically excluded
13022  {
13023  bool FirstPass = true; //added at v2.8.0
13024  while(OR.PrefDirSize() > 0)
13025  // remove the route up to but not including the next facing signal, in case a route extends to another signal
13026  {
13027  TPrefDirElement PDE = OR.GetFixedPrefDirElementAt(249, 0);
13028 // these will change at each element removal because OR is a reference to the real route
13029  int TVPos2 = PDE.GetTrackVectorPosition();
13030  if(FirstPass && (TVPos2 != FirstRouteElementVecPos)) //route is not directed away from cdt train, could be a call-on for another train (added at v2.8.0)
13031  {
13032  break;
13033  }
13034  TTrackElement TE2 = Track->TrackElementAt(1015, TVPos2);
13035  if(Track->TrackElementAt(1016, PDE.GetTrackVectorPosition()).Config[PDE.GetXLinkPos()] != Signal)
13036  {
13037  AllRoutes->RemoveRouteElement(24, TE2.HLoc, TE2.VLoc, PDE.GetELink());
13038  }
13039  else
13040  {
13041  break;
13042  }
13043  FirstPass = false;
13044  }
13045  AllRoutes->RebuildRailwayFlag = true;
13046  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to replot without stub route
13047  }
13048  }
13049  }
13050 // end of stub route removal addition
13051  }
13052  if(Train.MidElement > -1)
13053  {
13054  TrackElementPtr = &(Track->TrackElementAt(674, Train.MidElement));
13055  // remove TrainIDs from track element, added at v2.4.0
13056  if(TrackElementPtr->TrackType == Bridge)
13057  {
13058  if(Train.MidExitPos > 1)
13059  {
13060  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
13061  }
13062  else
13063  {
13064  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
13065  }
13066  }
13067  else
13068  {
13069  TrackElementPtr->TrainIDOnElement = -1;
13070  }
13071  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
13072  {
13073  TrackElementPtr->CallingOnSet = false;
13074  Track->PlotSignal(7, *TrackElementPtr, Display);
13075  }
13076 // [added at v1.3.0 as above]
13078  {
13079  RouteType = AllRoutes->GetRouteTypeAndNumber(28, Train.MidElement, Train.MidEntryPos, RouteNumber);
13080  if(RouteType == TAllRoutes::AutoSigsRoute)
13081  {
13084  }
13085  }
13086 // end of addition
13087  }
13088  if(Train.LeadElement > -1)
13089  // addition for v1.3.2 after Carwyn Thomas fault reported 24/05/15 - need to check if exiting at continuation (LeadElement == -1) as if so fails at next line
13090  {
13091  if(Track->TrackElementAt(675, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
13092  {
13093  TrackElementPtr = &(Track->TrackElementAt(676, Track->TrackElementAt(677, Train.LeadElement).Conn[Train.LeadExitPos]));
13094  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
13095  {
13096  TrackElementPtr->CallingOnSet = false;
13097  Track->PlotSignal(8, *TrackElementPtr, Display);
13098  }
13099  }
13100  }
13101  Train.LogAction(5, Train.HeadCode, "", RemoveTrain, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
13102  if(Train.ActionVectorEntryPtr->Command != "Frh") // if remaining at location no point in sending 'failed to terminate' message
13103  {
13104  Train.SendMissedActionLogs(0, -1, Train.ActionVectorEntryPtr); // -1 is a marker for send messages for all remaining
13105  } // entries, including Fer if present
13106 
13107  Utilities->CallLogPop(1200);
13108  }
13109  catch(const Exception &e)
13110  {
13111  ErrorLog(164, e.Message);
13112  }
13113 }
13114 
13115 // ---------------------------------------------------------------------------
13116 
13117 void __fastcall TInterface::ErrorButtonClick(TObject *Sender)
13118 // to terminate after error message given
13119 {
13120  ErrorMessage->Visible = false;
13121  ErrorMessageStoreImage->Visible = false;
13122  ErrorButton->Visible = false;
13123  Display->GetImage()->Visible = true;
13124  Application->Terminate();
13125 }
13126 
13127 // ---------------------------------------------------------------------------
13128 void __fastcall TInterface::PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
13129 {
13130  try
13131  {
13132  TrainController->LogEvent("PerformancePanelLabelStartDrag");
13133  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelLabelStartDrag");
13134  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
13135  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
13136  Utilities->CallLogPop(1202);
13137  }
13138  catch(const Exception &e)
13139  {
13140  ErrorLog(165, e.Message);
13141  }
13142 }
13143 // ---------------------------------------------------------------------------
13144 
13145 void __fastcall TInterface::FormClose(TObject *Sender, TCloseAction &Action)
13146 {
13147  try
13148  {
13149  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FormClose");
13150 /* Dropped at v2.9.1 as serves no apparent purpose
13151  if(!FileChangedFlag && !(Track->IsTrackFinished()) && (EveryPrefDir->PrefDirSize() > 0))
13152  {
13153  UnicodeString MessageStr =
13154  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
13155  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
13156  if(button == IDNO)
13157  {
13158  Action = caNone; // prevents form & application from closing
13159  Utilities->CallLogPop(1712);
13160  return;
13161  }
13162  }
13163 */
13165  {
13166  UnicodeString MessStr = "";
13168  {
13169  MessStr = UnicodeString("The railway and the timetable have both changed, exit without saving either?");
13170  }
13171  else if(FileChangedFlag)
13172  {
13173  MessStr = UnicodeString("The railway has changed, exit without saving?");
13174  }
13175  else
13176  {
13177  MessStr = UnicodeString("The timetable has changed, exit without saving?");
13178  }
13179  int button = Application->MessageBox(MessStr.c_str(), L"Please confirm", MB_YESNO);
13180  if(button == IDNO)
13181  {
13182  Action = caNone; // prevents form & application from closing
13183  Utilities->CallLogPop(1133);
13184  return;
13185  }
13186  }
13187  if(Level1Mode == OperMode)
13188  {
13190  {
13191  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
13192  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
13194  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
13195  TrainController->BaseTime = TDateTime::CurrentDateTime();
13197  if(button == IDNO)
13198  {
13199  Action = caNone; // prevents form & application from closing
13200  Utilities->CallLogPop(969);
13201  return;
13202  }
13203  }
13205  Utilities->PerformanceFile.close();
13206  }
13207  if((TempTTFileName != "") && FileExists(TempTTFileName))
13208  {
13209  DeleteFile(TempTTFileName);
13210  }
13211  Utilities->CallLogPop(971);
13212  }
13213  catch(const Exception &e)
13214  {
13215  ErrorLog(166, e.Message);
13216  }
13217 }
13218 
13219 // ---------------------------------------------------------------------------
13220 
13221 void __fastcall TInterface::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
13222 {
13223 // TrainController->LogEvent("FormKeyDown," + AnsiString(Key));
13224 // drop event log as have too many spurious entries
13225  try
13226  {
13227  if((Shift.Contains(ssAlt)) && (Shift.Contains(ssCtrl)))
13228  {
13229  if(Key == '2')
13230  {
13231  if(CallLogTickerLabel->Visible)
13232  {
13233  CallLogTickerLabel->Visible = false;
13234  }
13235  else
13236  {
13237  CallLogTickerLabel->Visible = true;
13238  }
13239  }
13240  else if(Key == '3')
13241  {
13242  if(DevelopmentPanel->Visible)
13243  {
13244  DevelopmentPanel->Visible = false;
13245  }
13246  else
13247  {
13248  DevelopmentPanel->Visible = true;
13249  DevelopmentPanel->BringToFront();
13250  }
13251  }
13252  else if(Key == '4')
13253  {
13254  TestFunction();
13255  }
13256  else if(Key == '5')
13257  {
13258  TMsgDlgButtons Buttons;
13259  Buttons << mbYes << mbNo;
13260  if(MessageDlg("Do you wish to allow facing signals next to bridges? If so please be aware that routes cannot be truncated to these signals.",
13261  mtWarning, Buttons, 0) == mrYes)
13262  {
13264  }
13265  else
13266  {
13268  }
13269  }
13270  }
13271  else if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
13272  {
13273  CtrlKey = true;
13274  }
13275  else if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
13276  {
13277  ShiftKey = true;
13278  }
13279 // below added at v1.3.0 to allow keyboard scrolling as well as mouse button scrolling - see user suggestion on Features & Requests forum 30/09/12
13280 // the NonCTRLOrSHIFTKeyUpFlag prevents repeated viewpoint movements without keys being re-pressed
13281 // note that use the OnKeyDown event rather than OnKeyPress as suggested by the user so that the CTRL & SHIFT keys can be taken into account
13282 
13283 // at v2.4.2 the flag changed to LastNonCtrlOrShiftKeyDown to make condition specific to last key, because when a message given the key up event
13284 // is not seen as the form does not have focus, so with the flag no shortcut key will work on the first press, with this only the same shortcut key
13285 // won't work on first press and that is less likely to be used a second time on either side of the message
13286 
13287  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
13288  {
13289  if(LastNonCtrlOrShiftKeyDown == Key) // same key still down rejected
13290  {
13291  return;
13292  }
13293  else
13294  {
13296  }
13297  }
13298  if(Key == VK_UP)
13299  {
13300  if(ScreenUpButton->Enabled)
13301  {
13302  ScreenUpButton->Click();
13303  }
13304  }
13305  else if(Key == VK_DOWN)
13306  {
13307  if(ScreenDownButton->Enabled)
13308  {
13309  ScreenDownButton->Click();
13310  }
13311  }
13312  else if(Key == VK_LEFT)
13313  {
13314  if(ScreenLeftButton->Enabled)
13315  {
13316  ScreenLeftButton->Click();
13317  }
13318  }
13319  else if(Key == VK_RIGHT)
13320  {
13321  if(ScreenRightButton->Enabled)
13322  {
13323  ScreenRightButton->Click();
13324  }
13325  }
13326  else if(Key == VK_HOME)
13327  {
13328  if(HomeButton->Enabled)
13329  {
13330  HomeButton->Click();
13331  }
13332  }
13333 // end of 1.3.0 addition
13334  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
13335  {
13336  if(ZoomButton->Enabled)
13337  {
13338  ZoomButton->Click();
13339  }
13340  }
13341  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
13342  {
13343  if(ZoomButton->Enabled)
13344  {
13345  ZoomButton->Click();
13346  }
13347  }
13348 // below added for v2.4.2 to add more keyboard shortcuts
13349  if(DistanceBox->Focused() || SpeedLimitBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
13350  SpeedEditBox2->Focused() || MTBFEditBox->Focused() || LocationNameTextBox->Focused() || TextBox->Focused() || PowerEditBox->Focused() ||
13351  SpeedEditBox->Focused() || AddSubMinsBox->Focused() || OneEntryTimetableMemo->Focused())
13352  {
13353  // prevent letter keys interfering when these boxes have focus - many are mutually exclusive but include them all
13354  return;
13355  }
13356  if(Shift.Contains(ssShift) && !Shift.Contains(ssAlt) && !Shift.Contains(ssCtrl) && NewHomeButton->Enabled && NewHomeButton->Visible)
13357  {
13358  if(Level1Mode != TimetableMode && (Key == 'H' || Key == 'h')) // TimetablePanel uses Shift H too so disable this when it's in use
13359  {
13360  NewHomeButton->Click();
13361  }
13362  }
13363 // Operating panel
13364  if(Level1Mode == OperMode && OperatingPanel->Enabled && OperatingPanel->Visible && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt) &&
13365  !MultiplayerPlayerPanel->Visible) //last condition added as these letters can be added in the edit boxes
13366  {
13367  // use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
13368  if(!Shift.Contains(ssCtrl))
13369  {
13370  if(OperateButton->Visible && OperateButton->Enabled)
13371  {
13372  if(Level2OperMode == Operating && (Key == 'P' || Key == 'p'))
13373  {
13374  OperateButton->Click();
13375  }
13376  else if((Level2OperMode == Paused || Level2OperMode == PreStart) && (Key == 'R' || Key == 'r'))
13377  {
13378  OperateButton->Click();
13379  }
13380  }
13381  if(PresetAutoSigRoutesButton->Visible && PresetAutoSigRoutesButton->Enabled && (Key == 'A' || Key == 'a'))
13382  {
13383  PresetAutoSigRoutesButton->Click();
13384  }
13385  if(PerformanceLogButton->Visible && PerformanceLogButton->Enabled && (Key == 'L' || Key == 'l'))
13386  {
13387  PerformanceLogButton->Click();
13388  }
13389  if(CallingOnButton->Visible && CallingOnButton->Enabled && (Key == 'O' || Key == 'o'))
13390  {
13391  CallingOnButton->Click();
13392  }
13393  if(OperatorActionButton->Visible && OperatorActionButton->Enabled && (Key == 'D' || Key == 'd'))
13394  {
13395  OperatorActionButton->Click();
13396  }
13397  if(RouteCancelButton->Visible && RouteCancelButton->Enabled && (Key == 'C' || Key == 'c'))
13398  {
13399  RouteCancelButton->Click();
13400  }
13401  if(TTClockAdjButton->Visible && TTClockAdjButton->Enabled && (Key == 'T' || Key == 't'))
13402  {
13403  TTClockAdjButton->Click();
13404  }
13405  if(AutoSigsButton->Visible && AutoSigsButton->Enabled && Key == '1') // route buttons - autosigs
13406  {
13407  AutoSigsButton->Click();
13408  }
13409  if(SigPrefConsecButton->Visible && SigPrefConsecButton->Enabled && Key == '2') // route buttons - prefdir
13410  {
13411  SigPrefConsecButton->Click();
13412  }
13413  if(SigPrefNonConsecButton->Visible && SigPrefNonConsecButton->Enabled && Key == '4') // added at v2.7.0 for prefdir & any following signal
13414  {
13415  SigPrefNonConsecButton->Click();
13416  }
13417  if(UnrestrictedButton->Visible && UnrestrictedButton->Enabled && Key == '3') // route buttons - unrestricted
13418  {
13419  UnrestrictedButton->Click();
13420  }
13421  if(ExitOperationButton->Visible && ExitOperationButton->Enabled && Key == '\x1b')
13422  {
13423  ExitOperationButton->Click();
13424  }
13425  }
13426  else // CtrlKey down
13427  {
13428  if(SaveSessionButton->Visible && SaveSessionButton->Enabled)
13429  {
13430  SaveMenuItem->ShortCut = 0;
13431 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
13432  if(Key == 'S' || Key == 's') // so this will never execute
13433  {
13434  SaveSessionButton->Click();
13435  }
13436  }
13437  }
13438  }
13439 // Timetable clock adjust panel
13440  if(Level1Mode == OperMode && TTClockAdjPanel->Enabled && TTClockAdjPanel->Visible && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
13441  {
13442  // use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
13443  if(Shift.Contains(ssShift))
13444  {
13445  if(TTClockExitButton->Visible && TTClockExitButton->Enabled && (Key == 'A' || Key == 'a'))
13446  {
13447  TTClockExitButton->Click();
13448  }
13449  if(TTClockResetButton->Visible && TTClockResetButton->Enabled && (Key == 'R' || Key == 'r'))
13450  {
13451  TTClockResetButton->Click();
13452  }
13453  }
13454  }
13455 // Track build panel
13456  if((Level1Mode == TrackMode) && TrackBuildPanel->Visible && TrackBuildPanel->Enabled)
13457  {
13458  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
13459  {
13460  if(AddTrackButton->Visible && AddTrackButton->Enabled && (Key == 'A' || Key == 'a')) // add/remove track elements
13461  {
13462  AddTrackButton->Click();
13463  }
13464  if(SigAspectButton->Visible && SigAspectButton->Enabled && (Key == 'S' || Key == 's')) // cycle through signal aspects
13465  {
13466  SigAspectButton->Click();
13467  }
13468  if(TrackOKButton->Visible && TrackOKButton->Enabled && (Key == 'L' || Key == 'l')) // link track
13469  {
13470  TrackOKButton->Click();
13471  }
13472  if(FontButton->Visible && FontButton->Enabled && (Key == 'F' || Key == 'f')) // change font
13473  {
13474  FontButton->Click();
13475  }
13476  if(LocationNameButton->Visible && LocationNameButton->Enabled && (Key == 'N' || Key == 'n')) // name locations
13477  {
13478  LocationNameButton->Click();
13479  }
13480  if(SetLengthsButton->Visible && SetLengthsButton->Enabled && (Key == 'D' || Key == 'd')) // set distances/speeds
13481  {
13482  SetLengthsButton->Click();
13483  }
13484  if(AddTextButton->Visible && AddTextButton->Enabled && (Key == 'T' || Key == 't')) // add text
13485  {
13486  AddTextButton->Click();
13487  }
13488  if(ScreenGridButton->Visible && ScreenGridButton->Enabled && (Key == 'G' || Key == 'g')) // toggle grid
13489  {
13490  ScreenGridButton->Click();
13491  }
13492  if(MoveTextOrGraphicButton->Visible && MoveTextOrGraphicButton->Enabled && (Key == 'M' || Key == 'm')) // move text or graphic
13493  {
13494  MoveTextOrGraphicButton->Click();
13495  }
13496  if(UserGraphicButton->Visible && UserGraphicButton->Enabled && (Key == 'I' || Key == 'i')) // insert image
13497  {
13498  UserGraphicButton->Click();
13499  }
13500  if(SetGapsButton->Visible && SetGapsButton->Enabled && (Key == 'J' || Key == 'j')) // join gaps
13501  {
13502  SetGapsButton->Click();
13503  }
13504  }
13505  if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
13506  {
13507  if(SaveRailwayTBPButton->Visible && SaveRailwayTBPButton->Enabled) // save railway in trackbuild mode
13508  {
13509  SaveMenuItem->ShortCut = 0;
13510 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
13511  if(Key == 'S' || Key == 's') // so this will never execute
13512  {
13513  SaveRailwayTBPButton->Click();
13514  }
13515  }
13516  }
13517  if(!Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
13518  {
13519  if((ExitTrackButton->Visible && ExitTrackButton->Enabled) && Key == '\x1b') // escape key
13520  {
13521  ExitTrackButton->Click();
13522  }
13523  }
13524  }
13525 // PrefDir panel
13526  if(Level1Mode == PrefDirMode && PrefDirPanel->Visible && PrefDirPanel->Enabled && !Shift.Contains(ssAlt))
13527  {
13528  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
13529  {
13530  if((ExitPrefDirButton->Visible && ExitPrefDirButton->Enabled) && Key == '\x1b') // escape key
13531  {
13532  ExitPrefDirButton->Click();
13533  }
13534  }
13535  if(!Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
13536  {
13537  if(SaveRailwayPDPButton->Visible && SaveRailwayPDPButton->Enabled)
13538  {
13539  SaveMenuItem->ShortCut = 0;
13540 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
13541  if(Key == 'S' || Key == 's') // so this will never execute
13542  {
13543  SaveRailwayPDPButton->Click();
13544  }
13545  }
13546  }
13547  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
13548  {
13549  if(AddPrefDirButton->Visible && AddPrefDirButton->Enabled && (Key == 'A' || Key == 'a')) // add pref dir
13550  {
13551  AddPrefDirButton->Click();
13552  }
13553  if(DeleteOnePrefDirButton->Visible && DeleteOnePrefDirButton->Enabled && (Key == 'D' || Key == 'd')) // delete one pref dir
13554  {
13555  DeleteOnePrefDirButton->Click();
13556  }
13557  if(DeleteAllPrefDirButton->Visible && DeleteAllPrefDirButton->Enabled && (Key == 'C' || Key == 'c')) // delete all pref dirs
13558  {
13559  DeleteAllPrefDirButton->Click();
13560  }
13561  }
13562  }
13563 // Note that save button in BaseMode is handled by Ctrl S from the File menu
13564 
13565 // Timetable panel
13566  if(Level1Mode == TimetableMode && TimetablePanel->Visible && TimetablePanel->Enabled && !Shift.Contains(ssAlt))
13567  {
13568  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
13569  {
13570  if(ExitTTModeButton->Visible && ExitTTModeButton->Enabled && Key == '\x1b') // escape key
13571  {
13572  ExitTTModeButton->Click();
13573  }
13574  }
13575  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl)) // show/hide timetable edit panel
13576  {
13577  if(ShowHideTTButton->Visible && ShowHideTTButton->Enabled)
13578  {
13579  if(!TimetableEditPanel->Visible)
13580  {
13581  if(Key == 'S' || Key == 's')
13582  {
13583  ShowHideTTButton->Click();
13584  }
13585  }
13586  else if(Key == 'H' || Key == 'h')
13587  {
13588  ShowHideTTButton->Click();
13589  }
13590  }
13591  }
13592  }
13593 // Timetable edit panel
13594 // These just set flags. The corresponding 'Click()' function executes separately to the keypress because Windows stores the key until after any directly linked key code
13595 // is executed then selects the timetable entry that begins with the letter corresponding to the key. Without this separation the list box is left with the wrong entry
13596 // showing. See DevHistory.txt for the version at v2.5.0 for details.
13597  if(Level1Mode == TimetableMode && TimetableEditPanel->Visible && TimetableEditPanel->Enabled && !Shift.Contains(ssAlt))
13598  {
13599  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
13600  {
13602 // store value here before the Windows key press function runs (it runs after any local code)
13603  if(PreviousTTEntryButton->Enabled && (Key == 'L' || Key == 'l'))
13604  {
13605  PreviousTTEntryKeyFlag = true;
13606  }
13607  if(NextTTEntryButton->Enabled && (Key == 'N' || Key == 'n'))
13608  {
13609  NextTTEntryKeyFlag = true;
13610  }
13611  if(MoveTTEntryUpButton->Enabled && (Key == 'U' || Key == 'u'))
13612  {
13613  MoveTTEntryUpKeyFlag = true;
13614  }
13615  if(MoveTTEntryDownButton->Enabled && (Key == 'D' || Key == 'd'))
13616  {
13617  MoveTTEntryDownKeyFlag = true;
13618  }
13619  if(CopyTTEntryButton->Enabled && (Key == 'C' || Key == 'c'))
13620  {
13621  CopyTTEntryKeyFlag = true;
13622  }
13623  if(CutTTEntryButton->Enabled && (Key == 'X' || Key == 'x'))
13624  {
13625  CutTTEntryKeyFlag = true;
13626  }
13627  if(PasteTTEntryButton->Enabled && (Key == 'P' || Key == 'p'))
13628  {
13629  PasteTTEntryKeyFlag = true;
13630  }
13631  if(DeleteTTEntryButton->Enabled && (Key == 'E' || Key == 'e'))
13632  {
13633  DeleteTTEntryKeyFlag = true;
13634  }
13635 /* if(SaveTTEntryButton->Enabled && (Key == 'E' || Key == 'e')) //can't have save while editing entry as adds the letter to the entry
13636  {
13637  SaveTTEntryKeyFlag = true;
13638  }
13639  if(CancelTTActionButton->Enabled && (Key == 'K' || Key == 'k')) //can't have cancel while editing entry as adds the letter to the entry
13640  {
13641  CancelTTActionKeyFlag = true;
13642  }
13643 */
13644  if(NewTTEntryButton->Enabled && (Key == 'I' || Key == 'i'))
13645  {
13646  NewTTEntryKeyFlag = true;
13647  }
13648  if(AZOrderButton->Enabled && (Key == 'Z' || Key == 'z'))
13649  {
13650  AZOrderKeyFlag = true;
13651  }
13652 /*
13653  if(AddMinsButton->Enabled && (Key == 'M' || Key == 'm')) //can't have key here as adds the letter to the entry
13654  {
13655  AddMinsKeyFlag = true;
13656  }
13657  if(SubMinsButton->Enabled && (Key == 'B' || Key == 'b')) //can't have key here as adds the letter to the entry
13658  {
13659  SubMinsKeyFlag = true;
13660  }
13661 */
13662  if(TTServiceSyntaxCheckButton->Enabled && (Key == 'Q' || Key == 'q'))
13663  {
13665  }
13666  if(ValidateTimetableButton->Enabled && (Key == 'V' || Key == 'v'))
13667  {
13668  ValidateTimetableKeyFlag = true;
13669  }
13670  if(SaveTTButton->Enabled && (Key == 'T' || Key == 't'))
13671  {
13672  SaveTTKeyFlag = true;
13673  }
13674  if(SaveTTAsButton->Enabled && (Key == 'A' || Key == 'a'))
13675  {
13676  SaveTTAsKeyFlag = true;
13677  }
13678  if(RestoreTTButton->Enabled && (Key == 'R' || Key == 'r'))
13679  {
13680  RestoreTTKeyFlag = true;
13681  }
13682  if(ExportTTButton->Enabled && (Key == 'O' || Key == 'o'))
13683  {
13684  ExportTTKeyFlag = true;
13685  }
13686  if(ConflictAnalysisButton->Enabled && (Key == 'F' || Key == 'f'))
13687  {
13688  ConflictAnalysisKeyFlag = true;
13689  }
13690  }
13691  }
13692 // Information menu
13693  if(FloatingInfoMenu->Enabled && !Shift.Contains(ssAlt) && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
13694  {
13695  if(Key == 'I' || Key == 'i') // toggle track info
13696  {
13697  TrackInfoOnOffMenuItem->Click();
13698  }
13699  else if(TrainInfoMenuItem->Enabled)
13700  {
13701  if(Key == 'S' || Key == 's') // toggle train status info
13702  {
13704  }
13705  else if(Key == 'T' || Key == 't') // toggle train timetable info
13706  {
13707  TrainTTInfoOnOffMenuItem->Click();
13708  }
13709  }
13710  }
13711 // end of 2.4.2 addition
13712 
13713  }
13714  catch(const Exception &e)
13715  {
13716  ErrorLog(167, e.Message);
13717  }
13718 }
13719 
13720 // ---------------------------------------------------------------------------
13721 
13722 void __fastcall TInterface::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13723 {
13724  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
13725  {
13726  LastNonCtrlOrShiftKeyDown = -1; // reset value to no key down
13727  }
13728  CtrlKey = false;
13729  ShiftKey = false;
13730  SaveMenuItem->ShortCut = 16467; // restore Ctrl S for save menu in case set to 0 in FormKeyDown
13731 }
13732 
13733 // ---------------------------------------------------------------------------
13734 
13735 void __fastcall TInterface::OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13736 {
13737  if((Button == mbRight) && Level2OperMode == Operating)
13738  {
13739  OutputLog1->Caption = "";
13740  }
13741 }
13742 
13743 // ---------------------------------------------------------------------------
13744 
13745 void __fastcall TInterface::OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13746 {
13747  if((Button == mbRight) && Level2OperMode == Operating)
13748  {
13749  OutputLog2->Caption = "";
13750  }
13751 }
13752 // ---------------------------------------------------------------------------
13753 
13754 void __fastcall TInterface::OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13755 {
13756  if((Button == mbRight) && Level2OperMode == Operating)
13757  {
13758  OutputLog3->Caption = "";
13759  }
13760 }
13761 
13762 // ---------------------------------------------------------------------------
13763 
13764 void __fastcall TInterface::OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13765 {
13766  if((Button == mbRight) && Level2OperMode == Operating)
13767  {
13768  OutputLog4->Caption = "";
13769  }
13770 }
13771 
13772 // ---------------------------------------------------------------------------
13773 
13774 void __fastcall TInterface::OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13775 {
13776  if((Button == mbRight) && Level2OperMode == Operating)
13777  {
13778  OutputLog5->Caption = "";
13779  }
13780 }
13781 // ---------------------------------------------------------------------------
13782 
13783 void __fastcall TInterface::OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13784 {
13785  if((Button == mbRight) && Level2OperMode == Operating)
13786  {
13787  OutputLog6->Caption = "";
13788  }
13789 }
13790 
13791 // ---------------------------------------------------------------------------
13792 
13793 void __fastcall TInterface::OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13794 {
13795  if((Button == mbRight) && Level2OperMode == Operating)
13796  {
13797  OutputLog7->Caption = "";
13798  }
13799 }
13800 
13801 // ---------------------------------------------------------------------------
13802 
13803 void __fastcall TInterface::OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13804 {
13805  if((Button == mbRight) && Level2OperMode == Operating)
13806  {
13807  OutputLog8->Caption = "";
13808  }
13809 }
13810 
13811 // ---------------------------------------------------------------------------
13812 
13813 void __fastcall TInterface::OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13814 {
13815  if((Button == mbRight) && Level2OperMode == Operating)
13816  {
13817  OutputLog9->Caption = "";
13818  }
13819 }
13820 
13821 // ---------------------------------------------------------------------------
13822 
13823 void __fastcall TInterface::OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
13824 {
13825  if((Button == mbRight) && Level2OperMode == Operating)
13826  {
13827  OutputLog10->Caption = "";
13828  }
13829 }
13830 
13831 // ---------------------------------------------------------------------------
13832 
13833 void __fastcall TInterface::AboutMenuItemClick(TObject *Sender)
13834 {
13835  try
13836  {
13837  if((Level1Mode == OperMode) && (Level2OperMode != PreStart))
13838  // if PreStart leave as is [Modified at v1.2.0 - formerly just 'if((Level1Mode == OperMode)']
13839  {
13841  SetLevel2OperMode(3);
13842  MasterClock->Enabled = false;
13843  }
13844  AboutForm->ShowModal();
13845  }
13846  catch(const Exception &e)
13847  {
13848  ErrorLog(168, e.Message);
13849  }
13850 }
13851 
13852 // ---------------------------------------------------------------------------
13853 
13854 void __fastcall TInterface::OpenHelpMenuItemClick(TObject *Sender)
13855 {
13856  try
13857  {
13858  // Helpfile allocated during construction of Interface
13859  Application->HelpKeyword(u"Introduction"); // added at v2.0.0 for .chm help file
13860  }
13861  catch(const Exception &e)
13862  {
13863  ErrorLog(175, e.Message);
13864  }
13865 }
13866 
13867 // ---------------------------------------------------------------------------
13868 
13869 void __fastcall TInterface::RailwayWebSiteMenuItemClick(TObject *Sender)
13870 {
13871  const UnicodeString Link = "http://www.railwayoperationsimulator.com";
13872  ::ShellExecute(Handle, NULL, (Link).c_str(), NULL, NULL, SW_SHOWNORMAL);
13873 }
13874 
13875 // ---------------------------------------------------------------------------
13876 
13877 void __fastcall TInterface::BlackBgndMenuItemClick(TObject *Sender)
13878 {
13879  try
13880  {
13881  TrainController->LogEvent("BlackBgndMenuItemClick");
13882  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlackBgndMenuItemClick");
13883  TColor OldTransparentColour = Utilities->clTransparent;
13884  Utilities->clTransparent = TColor(0);
13885  SelectBitmap->TransparentColor = Utilities->clTransparent;
13888 
13889  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
13890  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
13891  Level1Mode = BaseMode;
13892  SetLevel1Mode(128);
13893  Utilities->CallLogPop(1797);
13894  }
13895  catch(const Exception &e)
13896  {
13897  ErrorLog(170, e.Message);
13898  }
13899 }
13900 
13901 // ---------------------------------------------------------------------------
13902 
13903 void __fastcall TInterface::WhiteBgndMenuItemClick(TObject *Sender)
13904 {
13905  try
13906  {
13907  TrainController->LogEvent("WhiteBgndMenuItemClick");
13908  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",WhiteBgndMenuItemClick");
13909  TColor OldTransparentColour = Utilities->clTransparent;
13910  Utilities->clTransparent = TColor(0xFFFFFF);
13911  SelectBitmap->TransparentColor = Utilities->clTransparent;
13914 
13915  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
13916  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
13917  Level1Mode = BaseMode;
13918  SetLevel1Mode(129);
13919  Utilities->CallLogPop(1798);
13920  }
13921  catch(const Exception &e)
13922  {
13923  ErrorLog(171, e.Message);
13924  }
13925 }
13926 
13927 // ---------------------------------------------------------------------------
13928 
13929 void __fastcall TInterface::BlueBgndMenuItemClick(TObject *Sender)
13930 {
13931  try
13932  {
13933  TrainController->LogEvent("BlueBgndMenuItemClick");
13934  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlueBgndMenuItemClick");
13935  TColor OldTransparentColour = Utilities->clTransparent;
13936  Utilities->clTransparent = TColor(0x330000);
13937  SelectBitmap->TransparentColor = Utilities->clTransparent;
13940 
13941  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
13942  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
13943  Level1Mode = BaseMode;
13944  SetLevel1Mode(130);
13945  Utilities->CallLogPop(1799);
13946  }
13947  catch(const Exception &e)
13948  {
13949  ErrorLog(172, e.Message);
13950  }
13951 }
13952 
13953 // ---------------------------------------------------------------------------
13954 
13955 void __fastcall TInterface::SpeedToggleButtonClick(TObject *Sender)
13956 {
13957  if(SpeedTopLabel->Caption == "mph")
13958  {
13959  SpeedTopLabel->Caption = "km/h";
13960  SpeedBottomLabel->Caption = "mph";
13961  }
13962  else
13963  {
13964  SpeedTopLabel->Caption = "mph";
13965  SpeedBottomLabel->Caption = "km/h";
13966  }
13967  // swap values to match toggle state
13968  UnicodeString SavedTopValue = SpeedEditBox->Text;
13969  UnicodeString SavedBottomValue = SpeedVariableLabel->Caption;
13970 
13971  SpeedEditBox->Text = SavedBottomValue;
13972  SpeedVariableLabel->Caption = SavedTopValue;
13973 }
13974 // ---------------------------------------------------------------------------
13975 
13976 void __fastcall TInterface::SpeedToggleButton2Click(TObject *Sender)
13977 {
13978  if(SpeedTopLabel2->Caption == "mph")
13979  {
13980  SpeedTopLabel2->Caption = "km/h";
13981  SpeedBottomLabel2->Caption = "mph";
13982  }
13983  else
13984  {
13985  SpeedTopLabel2->Caption = "mph";
13986  SpeedBottomLabel2->Caption = "km/h";
13987  }
13988  // swap values to match toggle state
13989  UnicodeString SavedTopValue = SpeedEditBox2->Text;
13990  UnicodeString SavedBottomValue = SpeedVariableLabel2->Caption;
13991 
13992  SpeedEditBox2->Text = SavedBottomValue;
13993  SpeedVariableLabel2->Caption = SavedTopValue;
13994 }
13995 // ---------------------------------------------------------------------------
13996 
13997 void __fastcall TInterface::SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13998 {
13999  try
14000  {
14001  TrainController->LogEvent("SpeedEditBoxKeyUp," + AnsiString(Key));
14002  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBoxKeyUp," + AnsiString(Key));
14003  bool ErrorFlag = false, TooBigFlag = false;
14004  if(SpeedEditBox->Text.Length() > 0)
14005  {
14006  if(SpeedEditBox->Text.Length() > 5)
14007  {
14008  TooBigFlag = true;
14009  }
14010  for(int x = 1; x <= SpeedEditBox->Text.Length(); x++)
14011  {
14012  if((SpeedEditBox->Text[x] < '0') || (SpeedEditBox->Text[x] > '9'))
14013  {
14014  SpeedVariableLabel->Caption = "Entry error";
14015  ErrorFlag = true;
14016  break;
14017  }
14018  if(TooBigFlag)
14019  {
14020  SpeedVariableLabel->Caption = "Too big";
14021  break;
14022  }
14023  }
14024  if(!ErrorFlag && !TooBigFlag)
14025  {
14026 /*
14027  1 mph = 1.609344 km/h
14028  1 km/h = 0.621371 mph
14029 */
14030  if(SpeedTopLabel->Caption == "mph")
14031  {
14032  // do mph-to-km/h conversion
14033  int MPH = SpeedEditBox->Text.ToInt();
14034  int KPH = (MPH * 1.609344) + 0.5;
14035  SpeedVariableLabel->Caption = UnicodeString(KPH);
14036  }
14037  else
14038  {
14039  // do km/h-to-mph conversion
14040  int KPH = SpeedEditBox->Text.ToInt();
14041  int MPH = (KPH * 0.621371) + 0.5;
14042  SpeedVariableLabel->Caption = UnicodeString(MPH);
14043  }
14044  }
14045  }
14046  else
14047  {
14048  SpeedVariableLabel->Caption = "";
14049  }
14050  Utilities->CallLogPop(1865);
14051  }
14052  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non-error catch
14053  {
14054  SpeedVariableLabel->Caption = "Entry error";
14055  Utilities->CallLogPop(2307);
14056  }
14057  catch(const Exception &e)
14058  {
14059  ErrorLog(176, e.Message);
14060  }
14061 }
14062 
14063 // ---------------------------------------------------------------------------
14064 
14065 void __fastcall TInterface::PowerToggleButtonClick(TObject *Sender)
14066 {
14067  if(PowerTopLabel->Caption == "HP")
14068  {
14069  PowerTopLabel->Caption = "kW";
14070  PowerBottomLabel->Caption = "HP";
14071  }
14072  else
14073  {
14074  PowerTopLabel->Caption = "HP";
14075  PowerBottomLabel->Caption = "kW";
14076  }
14077  // swap values to match toggle state
14078  UnicodeString SavedTopValue = PowerEditBox->Text;
14079  UnicodeString SavedBottomValue = PowerVariableLabel->Caption;
14080 
14081  PowerEditBox->Text = SavedBottomValue;
14082  PowerVariableLabel->Caption = SavedTopValue;
14083 }
14084 // ---------------------------------------------------------------------------
14085 
14086 void __fastcall TInterface::PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
14087 {
14088  try
14089  {
14090  TrainController->LogEvent("PowerEditBoxKeyUp," + AnsiString(Key));
14091  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PowerEditBoxKeyUp," + AnsiString(Key));
14092  bool ErrorFlag = false, TooBigFlag = false;
14093  if(PowerEditBox->Text.Length() > 0)
14094  {
14095  if(PowerEditBox->Text.Length() > 8)
14096  {
14097  TooBigFlag = true;
14098  }
14099  for(int x = 1; x <= PowerEditBox->Text.Length(); x++)
14100  {
14101  if((PowerEditBox->Text[x] < '0') || (PowerEditBox->Text[x] > '9'))
14102  {
14103  PowerVariableLabel->Caption = "Entry error";
14104  ErrorFlag = true;
14105  break;
14106  }
14107  if(TooBigFlag)
14108  {
14109  PowerVariableLabel->Caption = "Too big";
14110  break;
14111  }
14112  }
14113  if(!ErrorFlag && !TooBigFlag)
14114  {
14115 /*
14116  1 kW = 1.340482574 HP
14117  1 HP = 0.745699872 kW
14118 */
14119  if(PowerTopLabel->Caption == "HP")
14120  {
14121  // do HP-to-kW conv
14122  int HP = PowerEditBox->Text.ToInt();
14123  int KW = (HP * 0.745699872) + 0.5;
14124  PowerVariableLabel->Caption = UnicodeString(KW);
14125  }
14126  else
14127  {
14128  // do kW-to-HP conv
14129  int KW = PowerEditBox->Text.ToInt();
14130  int HP = (KW * 1.340482574) + 0.5;
14131  PowerVariableLabel->Caption = UnicodeString(HP);
14132  }
14133  }
14134  }
14135  else
14136  {
14137  PowerVariableLabel->Caption = "";
14138  }
14139  Utilities->CallLogPop(1868);
14140  }
14141  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non-error catch
14142  {
14143  PowerVariableLabel->Caption = "Entry error";
14144  Utilities->CallLogPop(2308);
14145  }
14146  catch(const Exception &e)
14147  {
14148  ErrorLog(179, e.Message);
14149  }
14150 }
14151 // ---------------------------------------------------------------------------
14152 
14153 void __fastcall TInterface::SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
14154 {
14155  try
14156  {
14157  TrainController->LogEvent("SpeedEditBox2KeyUp," + AnsiString(Key));
14158  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBox2KeyUp," + AnsiString(Key));
14159  bool ErrorFlag = false, TooBigFlag = false;
14160  if(SpeedEditBox2->Text.Length() > 0)
14161  {
14162  if(SpeedEditBox2->Text.Length() > 5)
14163  {
14164  TooBigFlag = true;
14165  }
14166  for(int x = 1; x <= SpeedEditBox2->Text.Length(); x++)
14167  {
14168  if((SpeedEditBox2->Text[x] < '0') || (SpeedEditBox2->Text[x] > '9'))
14169  {
14170  SpeedVariableLabel2->Caption = "Entry error";
14171  ErrorFlag = true;
14172  break;
14173  }
14174  if(TooBigFlag)
14175  {
14176  SpeedVariableLabel2->Caption = "Too big";
14177  break;
14178  }
14179  }
14180  if(!ErrorFlag && !TooBigFlag)
14181  {
14182 /*
14183  1 mph = 1.609344 km/h
14184  1 km/h = 0.621371 mph
14185 */
14186  if(SpeedTopLabel2->Caption == "mph")
14187  {
14188  // do mph-to-km/h conversion
14189  int MPH = SpeedEditBox2->Text.ToInt();
14190  int KPH = (MPH * 1.609344) + 0.5;
14191  SpeedVariableLabel2->Caption = AnsiString(KPH);
14192  }
14193  else
14194  {
14195  // do km/h-to-mph conversion
14196  int KPH = SpeedEditBox2->Text.ToInt();
14197  int MPH = (KPH * 0.621371) + 0.5;
14198  SpeedVariableLabel2->Caption = AnsiString(MPH);
14199  }
14200  }
14201  }
14202  else
14203  {
14204  SpeedVariableLabel2->Caption = "";
14205  }
14206  Utilities->CallLogPop(1866);
14207  }
14208  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non-error catch
14209  {
14210  SpeedVariableLabel2->Caption = "Entry error";
14211  Utilities->CallLogPop(2309);
14212  }
14213  catch(const Exception &e)
14214  {
14215  ErrorLog(177, e.Message);
14216  }
14217 }
14218 
14219 // ---------------------------------------------------------------------------
14220 
14221 void __fastcall TInterface::LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
14222 {
14223  try
14224  {
14225  TrainController->LogEvent("LengthEditKeyUp," + AnsiString(Key));
14226  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthEditKeyUp," + AnsiString(Key));
14227  bool ErrorFlag = false, TooLongFlag = false;
14228  if((MileEdit->Text.Length() > 0) && (MileEdit->Text.Length() < 6))
14229  {
14230  for(int x = 1; x <= MileEdit->Text.Length(); x++)
14231  {
14232  if((MileEdit->Text[x] < '0') || (MileEdit->Text[x] > '9'))
14233  {
14234  MetreVariableLabel->Caption = "Entry error";
14235  ErrorFlag = true;
14236  break;
14237  }
14238  }
14239  }
14240  if((ChainEdit->Text.Length() > 0) && (ChainEdit->Text.Length() < 6))
14241  {
14242  for(int x = 1; x <= ChainEdit->Text.Length(); x++)
14243  {
14244  if((ChainEdit->Text[x] < '0') || (ChainEdit->Text[x] > '9'))
14245  {
14246  MetreVariableLabel->Caption = "Entry error";
14247  ErrorFlag = true;
14248  break;
14249  }
14250  }
14251  }
14252  if((YardEdit->Text.Length() > 0) && (YardEdit->Text.Length() < 6))
14253  {
14254  for(int x = 1; x <= YardEdit->Text.Length(); x++)
14255  {
14256  if((YardEdit->Text[x] < '0') || (YardEdit->Text[x] > '9'))
14257  {
14258  MetreVariableLabel->Caption = "Entry error";
14259  ErrorFlag = true;
14260  break;
14261  }
14262  }
14263  }
14264  if((MileEdit->Text.Length() > 5) || (ChainEdit->Text.Length() > 5) || (YardEdit->Text.Length() > 5))
14265  {
14266  TooLongFlag = true;
14267  MetreVariableLabel->Caption = "Too big";
14268  }
14269  if(!ErrorFlag && !TooLongFlag)
14270  {
14271  int Miles = 0, Chains = 0, Yards = 0, Metres = 0;
14272  if(MileEdit->Text.Length() > 0)
14273  {
14274  Miles = MileEdit->Text.ToInt();
14275  }
14276  if(ChainEdit->Text.Length() > 0)
14277  {
14278  Chains = ChainEdit->Text.ToInt();
14279  }
14280  if(YardEdit->Text.Length() > 0)
14281  {
14282  Yards = YardEdit->Text.ToInt();
14283  }
14284  Metres = int((Miles * 1609.344) + (Chains * 20.1168) + (Yards * 0.9144) + 0.5);
14285  MetreVariableLabel->Caption = AnsiString(Metres);
14286  }
14287  if((MileEdit->Text.Length() == 0) && (ChainEdit->Text.Length() == 0) && (YardEdit->Text.Length() == 0))
14288  {
14289  MetreVariableLabel->Caption = "";
14290  }
14291  Utilities->CallLogPop(1867);
14292  }
14293  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non-error catch
14294  {
14295  MetreVariableLabel->Caption = "Entry error";
14296  Utilities->CallLogPop(2310);
14297  }
14298  catch(const Exception &e)
14299  {
14300  ErrorLog(178, e.Message);
14301  }
14302 }
14303 
14304 // ---------------------------------------------------------------------------
14305 
14306 void __fastcall TInterface::TTClockAdjButtonClick(TObject *Sender)
14307 {
14308  try
14309  {
14310  TrainController->LogEvent("TTClockAdjButtonClick");
14311  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjButtonClick");
14312 // Utilities->Clock2Stopped = true; // to keep panel buttons disabled, restarted on exit
14313  Display->HideWarningLog(0); // because this panel overwrites it
14314  TTClockAdjPanel->Visible = true;
14315  TTClockAdjButton->Enabled = false;
14316 /*
14317  OperatingPanelLabel->Caption = "Disabled"; all these now dealt with in ClockTimer2
14318  OperatingPanel->Enabled = false;
14319  ZoomButton->Enabled = false;
14320  HomeButton->Enabled = false;
14321  NewHomeButton->Enabled = false;
14322  ScreenLeftButton->Enabled = false;
14323  ScreenRightButton->Enabled = false;
14324  ScreenUpButton->Enabled = false;
14325  ScreenDownButton->Enabled = false;
14326 */
14327  Utilities->CallLogPop(1875);
14328  }
14329  catch(const Exception &e)
14330  {
14331  ErrorLog(181, e.Message);
14332  }
14333 }
14334 
14335 // ---------------------------------------------------------------------------
14336 
14337 void __fastcall TInterface::TTClockExitButtonClick(TObject *Sender)
14338 {
14339  try
14340  {
14341  TrainController->LogEvent("TTClockExitButtonClick");
14342  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockExitButtonClick");
14343  TTClockAdjPanel->Visible = false;
14344  TTClockAdjButton->Enabled = true;
14345 /* these dealt with in ClockTimer2
14346  ZoomButton->Enabled = true;
14347  HomeButton->Enabled = true;
14348  NewHomeButton->Enabled = true;
14349  ScreenLeftButton->Enabled = true;
14350  ScreenRightButton->Enabled = true;
14351  ScreenUpButton->Enabled = true;
14352  ScreenDownButton->Enabled = true;
14353  OperatingPanel->Enabled = true;
14354  OperatingPanelLabel->Caption = "Operation";
14355 */
14356  Display->ShowWarningLog(0);
14357  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
14358  if((TTClockSpeed != PauseEntryTTClockSpeed) || (TTClockTimeChange > 0.000347))
14359  {
14360  // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
14362  {
14363  TTClockAdjustWarningPanel->Top = MainScreen->Top + ((MainScreen->Height - TTClockAdjustWarningPanel->Height) / 2);
14364  TTClockAdjustWarningPanel->Left = MainScreen->Left + ((MainScreen->Width - TTClockAdjustWarningPanel->Width) / 2);
14365  TTClockAdjustWarningLabel->Caption =
14366  "Changes have been made to the timetable clock - you may wish to save a session before resuming operation.\n\nTo cancel all changes re-click the 'Adjust the timetable clock' button then click the reset button BEFORE resuming operation.";
14367  TTClockAdjustWarningPanel->Visible = true;
14368  }
14369  }
14370 // Utilities->Clock2Stopped = false; // as above
14372 // to restore the ability to reselect T after adj panel hidden (FormKeyUp doesn't work because the Interface form doesn't have focus)
14373  Utilities->CallLogPop(1876);
14374  }
14375  catch(const Exception &e)
14376  {
14377  ErrorLog(182, e.Message);
14378  }
14379 }
14380 // ---------------------------------------------------------------------------
14381 
14382 void __fastcall TInterface::TTClockx2ButtonClick(TObject *Sender)
14383 {
14384  try
14385  {
14386  TrainController->LogEvent("TTClockx2ButtonClick");
14387  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx2ButtonClick");
14388  TTClockSpeed = 2;
14389  TTClockSpeedLabel->Caption = "x2";
14391  Utilities->CallLogPop(1878);
14392  }
14393  catch(const Exception &e)
14394  {
14395  ErrorLog(184, e.Message);
14396  }
14397 }
14398 
14399 // ---------------------------------------------------------------------------
14400 
14401 void __fastcall TInterface::TTClockx4ButtonClick(TObject *Sender)
14402 {
14403  try
14404  {
14405  TrainController->LogEvent("TTClockx4ButtonClick");
14406  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx4ButtonClick");
14407  TTClockSpeed = 4;
14408  TTClockSpeedLabel->Caption = "x4";
14410  Utilities->CallLogPop(1883);
14411  }
14412  catch(const Exception &e)
14413  {
14414  ErrorLog(189, e.Message);
14415  }
14416 }
14417 
14418 // ---------------------------------------------------------------------------
14419 
14420 void __fastcall TInterface::TTClockx8ButtonClick(TObject *Sender)
14421 {
14422  try
14423  {
14424  TrainController->LogEvent("TTClockx8ButtonClick");
14425  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx8ButtonClick");
14426  TTClockSpeed = 8;
14427  TTClockSpeedLabel->Caption = "x8";
14429  Utilities->CallLogPop(1884);
14430  }
14431  catch(const Exception &e)
14432  {
14433  ErrorLog(190, e.Message);
14434  }
14435 }
14436 
14437 // ---------------------------------------------------------------------------
14438 
14439 void __fastcall TInterface::TTClockx16ButtonClick(TObject *Sender)
14440 {
14441  try
14442  {
14443  TrainController->LogEvent("TTClockx16ButtonClick");
14444  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx16ButtonClick");
14445  TTClockSpeed = 16;
14446  TTClockSpeedLabel->Caption = "x16";
14448  Utilities->CallLogPop(1885);
14449  }
14450  catch(const Exception &e)
14451  {
14452  ErrorLog(191, e.Message);
14453  }
14454 }
14455 
14456 // ---------------------------------------------------------------------------
14457 
14458 void __fastcall TInterface::TTClockx1ButtonClick(TObject *Sender)
14459 {
14460  try
14461  {
14462  TrainController->LogEvent("TTClockx1ButtonClick");
14463  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx1ButtonClick");
14464  TTClockSpeed = 1;
14465  TTClockSpeedLabel->Caption = "x1";
14467  Utilities->CallLogPop(1886);
14468  }
14469  catch(const Exception &e)
14470  {
14471  ErrorLog(192, e.Message);
14472  }
14473 }
14474 
14475 // ---------------------------------------------------------------------------
14476 
14477 void __fastcall TInterface::TTClockxHalfButtonClick(TObject *Sender)
14478 {
14479  try
14480  {
14481  TrainController->LogEvent("TTClockxHalfButtonClick");
14482  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxHalfButtonClick");
14483  TTClockSpeed = 0.5;
14484  TTClockSpeedLabel->Caption = "x1/2";
14486  Utilities->CallLogPop(1887);
14487  }
14488  catch(const Exception &e)
14489  {
14490  ErrorLog(193, e.Message);
14491  }
14492 }
14493 
14494 // ---------------------------------------------------------------------------
14495 
14496 void __fastcall TInterface::TTClockxQuarterButtonClick(TObject *Sender)
14497 {
14498  try
14499  {
14500  TrainController->LogEvent("TTClockxQuarterButtonClick");
14501  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxQuarterButtonClick");
14502  TTClockSpeed = 0.25;
14503  TTClockSpeedLabel->Caption = "x1/4";
14505  Utilities->CallLogPop(1888);
14506  }
14507  catch(const Exception &e)
14508  {
14509  ErrorLog(194, e.Message);
14510  }
14511 }
14512 
14513 // ---------------------------------------------------------------------------
14514 
14515 void __fastcall TInterface::TTClockxEighthButtonClick(TObject *Sender)
14516 {
14517  // added for v2.3.0 for very big railways
14518  try
14519  {
14520  TrainController->LogEvent("TTClockxEighthButtonClick");
14521  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxEighthButtonClick");
14522  TTClockSpeed = 0.125;
14523  TTClockSpeedLabel->Caption = "x1/8";
14525  Utilities->CallLogPop(2099);
14526  }
14527  catch(const Exception &e)
14528  {
14529  ErrorLog(203, e.Message);
14530  }
14531 }
14532 // ---------------------------------------------------------------------------
14533 
14534 void __fastcall TInterface::TTClockxSixteenthButtonClick(TObject *Sender)
14535 {
14536  // added for v2.3.0 for very big railways
14537  try
14538  {
14539  TrainController->LogEvent("TTClockxSixteenthButtonClick");
14540  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxSixteenthButtonClick");
14541  TTClockSpeed = 0.0625;
14542  TTClockSpeedLabel->Caption = "x1/16";
14544  Utilities->CallLogPop(2100);
14545  }
14546  catch(const Exception &e)
14547  {
14548  ErrorLog(204, e.Message);
14549  }
14550 }
14551 
14552 // ---------------------------------------------------------------------------
14553 
14554 void __fastcall TInterface::TTClockAdd1hButtonClick(TObject *Sender)
14555 {
14556  try
14557  {
14558  TrainController->LogEvent("TTClockAdd1hButtonClick");
14559  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1hButtonClick");
14560  double TTClockIncrement = 1.0 / 24;
14561  TrainController->RestartTime += TDateTime(TTClockIncrement);
14564  Utilities->CallLogPop(1879);
14565  }
14566  catch(const Exception &e)
14567  {
14568  ErrorLog(185, e.Message);
14569  }
14570 }
14571 
14572 // ---------------------------------------------------------------------------
14573 
14574 void __fastcall TInterface::TTClockAdd10mButtonClick(TObject *Sender)
14575 {
14576  try
14577  {
14578  TrainController->LogEvent("TTClockAdd10mButtonClick");
14579  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd10mButtonClick");
14580  double TTClockIncrement = 1.0 / 144;
14581  TrainController->RestartTime += TDateTime(TTClockIncrement);
14584  Utilities->CallLogPop(1881);
14585  }
14586  catch(const Exception &e)
14587  {
14588  ErrorLog(187, e.Message);
14589  }
14590 }
14591 
14592 // ---------------------------------------------------------------------------
14593 
14594 void __fastcall TInterface::TTClockAdd1mButtonClick(TObject *Sender)
14595 {
14596  try
14597  {
14598  TrainController->LogEvent("TTClockAdd1mButtonClick");
14599  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1mButtonClick");
14600  double TTClockIncrement = 1.0 / 1440;
14601  TrainController->RestartTime += TDateTime(TTClockIncrement);
14604  Utilities->CallLogPop(1882);
14605  }
14606  catch(const Exception &e)
14607  {
14608  ErrorLog(188, e.Message);
14609  }
14610 }
14611 
14612 // ---------------------------------------------------------------------------
14613 
14614 void __fastcall TInterface::TTClockResetButtonClick(TObject *Sender)
14615 {
14616  try
14617  {
14618  TrainController->LogEvent("TTClockResetButtonClick");
14619  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockResetButtonClick");
14624  if(TTClockSpeed == 2)
14625  {
14626  TTClockSpeedLabel->Caption = "x2";
14627  }
14628  else if(TTClockSpeed == 4)
14629  {
14630  TTClockSpeedLabel->Caption = "x4";
14631  }
14632  else if(TTClockSpeed == 8)
14633  {
14634  TTClockSpeedLabel->Caption = "x8";
14635  }
14636  else if(TTClockSpeed == 16)
14637  {
14638  TTClockSpeedLabel->Caption = "x16";
14639  }
14640  else if(TTClockSpeed == 0.5)
14641  {
14642  TTClockSpeedLabel->Caption = "x1/2";
14643  }
14644  else if(TTClockSpeed == 0.25)
14645  {
14646  TTClockSpeedLabel->Caption = "x1/4";
14647  }
14648  else if(TTClockSpeed == 0.125)
14649  {
14650  TTClockSpeedLabel->Caption = "x1/8";
14651  }
14652  else if(TTClockSpeed == 0.0625)
14653  {
14654  TTClockSpeedLabel->Caption = "x1/16";
14655  }
14656  else
14657  {
14658  TTClockSpeed = 1;
14659  TTClockSpeedLabel->Caption = "x1";
14660  }
14661  Utilities->CallLogPop(1880);
14662  }
14663  catch(const Exception &e)
14664  {
14665  ErrorLog(186, e.Message);
14666  }
14667 }
14668 
14669 // ---------------------------------------------------------------------------
14670 
14671 void __fastcall TInterface::PresetAutoSigRoutesButtonClick(TObject *Sender)
14672 {
14673  try
14674  {
14675  TrainController->LogEvent("PresetAutoSigRoutesButtonClick");
14676  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PresetAutoSigRoutesButtonClick");
14677  InfoPanel->Caption = "PRE-START: Presetting automatic signal routes";
14678  OperatingPanelLabel->Caption = "Disabled";
14679  OperatingPanel->Enabled = false; // becomes re-enabled during the call to ClockTimer2
14680  ZoomButton->Enabled = false;
14681  HomeButton->Enabled = false;
14682  NewHomeButton->Enabled = false;
14683  ScreenLeftButton->Enabled = false;
14684  ScreenRightButton->Enabled = false;
14685  ScreenUpButton->Enabled = false;
14686  ScreenDownButton->Enabled = false;
14687 
14688  Screen->Cursor = TCursor(-11); // Hourglass
14689  TPrefDirElement StartElement, EndElement;
14690  bool PointsChanged, AtLeastOneSet = false;
14691  int LastIteratorValue = 0;
14692  while(true)
14693  {
14694  if(!EveryPrefDir->GetStartAndEndPrefDirElements(0, StartElement, EndElement, LastIteratorValue))
14695  {
14696  break;
14697  }
14698  // rest of routine here - i.e. build the routes
14699  ConstructRoute->ClearRoute(); // in case not empty though should be
14700  AtLeastOneSet = true;
14701  if(ConstructRoute->GetPreferredRouteStartElement(1, StartElement.HLoc, StartElement.VLoc, EveryPrefDir, true)) // true for AutoSigsFlag
14702  {
14703  }
14704  if(ConstructRoute->GetNextPreferredRouteElement(1, EndElement.HLoc, EndElement.VLoc, EveryPrefDir, true, true, ConstructRoute->ReqPosRouteID,
14705  PointsChanged))
14706  {
14707  }
14709  }
14710  if(AtLeastOneSet)
14711  {
14714  }
14715  else
14716  {
14717  ShowMessage("No presettable automatic signal routes are available");
14718  }
14719  Screen->Cursor = TCursor(-2); // Arrow
14720  Utilities->CallLogPop(1994);
14721  }
14722  catch(const Exception &e)
14723  {
14724  ErrorLog(195, e.Message);
14725  }
14726 }
14727 
14728 // ---------------------------------------------------------------------------
14729 
14730 void __fastcall TInterface::FormResize(TObject *Sender) // new at v2.1.0
14731 {
14732  try
14733  {
14734  if(!SkipFormResizeEvent) // to avoid calling during startup and especially during shutdown
14735  {
14736  // else fails on shutdown because HiddenScreen & other things no longer exist
14737  int DispW = (Interface->Width - 64 - 16) / 16;
14738 // will truncate down to a multiple of 16 (64 = side panels and 16 compensates for excess width of Interface)
14739  int DispH = (Interface->Height - 192) / 16;
14740  MainScreen->Width = DispW * 16;
14741  MainScreen->Height = DispH * 16;
14742  Utilities->ScreenElementWidth = DispW;
14743  Utilities->ScreenElementHeight = DispH;
14744  HiddenScreen->Width = MainScreen->Width;
14745  HiddenScreen->Height = MainScreen->Height;
14746  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
14747  PerformancePanel->Left = MainScreen->Left;
14748  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new at v2.2.0
14749  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
14750  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
14751  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height; // new v2.2.0
14752  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; // new v2.2.0
14753  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 32; // new v2.4.0 32 is to place it above the positional panel
14754  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
14755  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
14756  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
14757  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
14758 
14759  if(!Display->ZoomOutFlag)
14760  {
14762  }
14763  else
14764  {
14765  Display->ClearDisplay(11);
14767  }
14768  Display->Update();
14769  }
14770  }
14771  catch(const Exception &e)
14772  {
14773  ErrorLog(197, e.Message);
14774  }
14775 }
14776 
14777 // ---------------------------------------------------------------------------
14778 
14779 void __fastcall TInterface::OperatorActionButtonClick(TObject *Sender)
14780 {
14781  try
14782  {
14783  TrainController->LogEvent("OperatorActionButtonClick");
14784  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionButtonClick");
14786  {
14787  ShowOperatorActionPanel = true;
14788  OperatorActionPanel->Visible = true;
14790  OperatorActionButton->Glyph->LoadFromResourceName(0, "HideOpActionPanel");
14791  }
14792  else
14793  {
14794  ShowOperatorActionPanel = false;
14795  OperatorActionPanel->Visible = false;
14797  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
14798  }
14799  Utilities->CallLogPop(2073);
14800  }
14801  catch(const Exception &e)
14802  {
14803  ErrorLog(199, e.Message);
14804  }
14805 }
14806 
14807 // ---------------------------------------------------------------------------
14808 
14810 {
14811  try
14812  {
14813  TrainController->LogEvent("ConvertToOtherHandSignalsMenuItemClick");
14814  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConvertToOtherHandSignalsMenuItemClick");
14816  if(Utilities->RHSignalFlag) // RH sigs after conversion
14817  {
14818  ConvertToOtherHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
14820  {
14822  }
14823  else
14824  {
14826  }
14827  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
14828  SigsOnLeftImage1->Visible = false;
14829  SigsOnLeftImage2->Visible = false;
14830  SigsOnRightImage1->Visible = true;
14831  SigsOnRightImage2->Visible = true;
14832  }
14833  else // LH sigs after conversion
14834  {
14835  ConvertToOtherHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
14837  {
14839  }
14840  else
14841  {
14843  }
14844  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
14845  SigsOnRightImage1->Visible = false;
14846  SigsOnRightImage2->Visible = false;
14847  SigsOnLeftImage1->Visible = true;
14848  SigsOnLeftImage2->Visible = true;
14849  }
14850  Utilities->CallLogPop(2097);
14851  }
14852  catch(const Exception &e)
14853  {
14854  ErrorLog(202, e.Message);
14855  }
14856 }
14857 // ---------------------------------------------------------------------------
14858 
14859 void __fastcall TInterface::MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
14860 
14861 {
14862  try
14863  {
14864  TrainController->LogEvent("MTBFEditBoxKeyUp," + AnsiString(Key));
14865  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxKeyUp," + AnsiString(Key));
14866  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
14867  {
14868  Utilities->CallLogPop(2160);
14869  return;
14870  }
14871  bool TooBigFlag = false, BadCharsFlag = false;
14874  if(MTBFEditBox->Text.Length() > 0)
14875  {
14876  for(int x = 1; x <= MTBFEditBox->Text.Length(); x++)
14877  {
14878  if((MTBFEditBox->Text[x] < '0') || (MTBFEditBox->Text[x] > '9'))
14879  {
14880  BadCharsFlag = true;
14881  break;
14882  }
14883  }
14884  if(!BadCharsFlag)
14885  {
14886  if(StrToInt(MTBFEditBox->Text) > 10000)
14887  {
14888  TooBigFlag = true;
14889  }
14890  }
14891  if(TooBigFlag)
14892  {
14893  ShowMessage("Maximum value allowed is 9999"); //changed from 10,000 at v 2.10.0 but length limited to 4 anyway so 'to big' shouldn't arise
14894  MTBFEditBox->Text = "";
14897  Utilities->CallLogPop(2161);
14898  return;
14899  }
14900  if(BadCharsFlag)
14901  {
14902  ShowMessage("Value must be a whole number with no special characters");
14903  MTBFEditBox->Text = "";
14906  Utilities->CallLogPop(2162);
14907  return;
14908  }
14909  TrainController->AvHoursIntValue = StrToInt(MTBFEditBox->Text); // ok if user enters 0 as that means no failures
14911  }
14913  {
14914  MTBFEditBox->Text = "";
14916  }
14917  Utilities->CallLogPop(2163);
14918  }
14919  catch(const Exception &e)
14920  {
14921  ErrorLog(209, e.Message);
14922  }
14923 }
14924 
14925 // ---------------------------------------------------------------------------
14926 
14927 void __fastcall TInterface::MTBFEditBoxClick(TObject *Sender)
14928 {
14929  try
14930  {
14931  TrainController->LogEvent("MTBFEditBoxClick");
14932  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
14933  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
14934  {
14935  MTBFEditBox->ReadOnly = true; // it should be anyway but include here for safety
14937  "Values can only be entered or changed in Pre-Start mode\ni.e. after selecting 'Operate railway' but before clicking 'Run'");
14938  }
14939  Utilities->CallLogPop(2164);
14940  }
14941  catch(const Exception &e)
14942  {
14943  ErrorLog(210, e.Message);
14944  }
14945 }
14946 
14947 // ---------------------------------------------------------------------------
14948 
14949 void __fastcall TInterface::UserGraphicButtonClick(TObject *Sender)
14950 {
14951  try
14952  {
14953  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
14954  LengthConversionPanel->Visible = false;
14955  SpeedConversionPanel->Visible = false;
14956  DistanceKey->Visible = false;
14957  TrackElementPanel->Visible = false;
14958  SigAspectButton->Enabled = false;
14960  SetLevel2TrackMode(63);
14961  Display->Update();
14962  if((SelectedGraphicFileName != "") && (!Track->UserGraphicVector.empty()))
14963  // latter condition added at v2.6.0 because showed after ClearAll & reselect failed
14964  {
14965  UserGraphicReselectPanel->Visible = true;
14966  }
14967  else
14968  {
14969  UserGraphicReselectPanel->Visible = false;
14970  LoadUserGraphic(0);
14971  }
14972  Utilities->CallLogPop(2183);
14973  }
14974  catch(const Exception &e)
14975  {
14976  ErrorLog(212, e.Message);
14977  }
14978 }
14979 
14980 // ---------------------------------------------------------------------------
14981 
14982 void __fastcall TInterface::ReselectUserGraphicClick(TObject *Sender)
14983 {
14984  try
14985  {
14986  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectUserGraphicClick");
14987  TrainController->LogEvent("ReselectUserGraphicClick " + SelectedGraphicFileName);
14988  UserGraphicReselectPanel->Visible = false;
14989  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
14990  if(UGMIt == Track->UserGraphicMap.end())
14991  {
14992  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
14993  Utilities->CallLogPop(2196);
14994  return;
14995  }
14997  SetLevel2TrackMode(64);
14998  Utilities->CallLogPop(2184);
14999  }
15000  catch(const Exception &e)
15001  {
15002  ErrorLog(213, e.Message);
15003  }
15004 }
15005 // ---------------------------------------------------------------------------
15006 
15007 void __fastcall TInterface::SelectNewGraphicClick(TObject *Sender)
15008 {
15009  try
15010  {
15011  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectNewGraphicClick");
15012  UserGraphicReselectPanel->Visible = false;
15013  LoadUserGraphic(1);
15014  Utilities->CallLogPop(2185);
15015  }
15016  catch(const Exception &e)
15017  {
15018  ErrorLog(214, e.Message);
15019  }
15020 }
15021 
15022 // ---------------------------------------------------------------------------
15023 
15024 void __fastcall TInterface::TTClockAdjustOKButtonClick(TObject *Sender)
15025 {
15026  try
15027  {
15028  TrainController->LogEvent("TTClockAdjustOKButtonClick");
15029  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjustOKButtonClick");
15030  TTClockAdjustWarningPanel->Visible = false;
15031  if(TTClockAdjustCheckBox->Checked)
15032  {
15033  TTClockAdjustWarningHide = true;
15034  }
15035  Utilities->CallLogPop(2219);
15036  }
15037  catch(const Exception &e)
15038  {
15039  ErrorLog(216, e.Message);
15040  }
15041 }
15042 
15043 // ---------------------------------------------------------------------------
15044 
15045 void __fastcall TInterface::TwoLocationNameButtonClick(TObject *Sender)
15046 {
15047  try
15048  {
15049  TrainController->LogEvent("TwoLocationNameButtonClick");
15050  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TwoLocationNameButtonClick");
15051  TwoLocationNamePanel->Visible = false;
15052  ShowHideTTButton->Enabled = true;
15053  ExitTTModeButton->Enabled = true;
15054  TimetableEditPanel->Enabled = true;
15055  if(TwoLocationNameCheckBox->Checked)
15056  {
15057  TwoLocationNamePanelHide = true;
15058  }
15059  Utilities->CallLogPop(2316);
15060  }
15061  catch(const Exception &e)
15062  {
15063  ErrorLog(224, e.Message);
15064  }
15065 }
15066 
15067 //---------------------------------------------------------------------------
15068 
15069 void __fastcall TInterface::ConflictAnalysisButtonClick(TObject *Sender)
15070 {
15071  try
15072  {
15073  TrainController->LogEvent("ConflictAnalysisButtonClick");
15074  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConflictAnalysisButtonClick");
15075  ConflictPanel->Visible = true;
15076  Utilities->CallLogPop(2220);
15077  }
15078  catch(const Exception &e)
15079  {
15080  ErrorLog(217, e.Message);
15081  }
15082 }
15083 
15084 // ---------------------------------------------------------------------------
15085 
15086 void __fastcall TInterface::CPCancelButtonClick(TObject *Sender)
15087 {
15088  try
15089  {
15090  TrainController->LogEvent("CPCancelButtonClick");
15091  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPCancelButtonClick");
15092  ConflictPanel->Visible = false;
15093  Utilities->CallLogPop(2221);
15094  }
15095  catch(const Exception &e)
15096  {
15097  ErrorLog(218, e.Message);
15098  }
15099 }
15100 
15101 // ---------------------------------------------------------------------------
15102 
15103 void __fastcall TInterface::CPGenFileButtonClick(TObject *Sender)
15104 {
15105  try
15106  {
15107  TrainController->LogEvent("CPGenFileButtonClick");
15108  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPGenFileButtonClick");
15109  if(!CPArrivalsCheckBox->Checked && !CPDeparturesCheckBox->Checked && !CPAtLocCheckBox->Checked && !CPDirectionsCheckBox->Checked)
15110  {
15111  ShowMessage("No boxes ticked!");
15112  }
15113  else // keep ticks & range values from last time, only reset on startup
15114  {
15115  Screen->Cursor = TCursor(-11); // hourglass
15116  AnsiString TTTitle;
15118  {
15119  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
15120  {
15121  if(CreateEditTTFileName[x] == '\\')
15122  {
15123  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
15124  break;
15125  }
15126  }
15128  CPAtLocCheckBox->Checked, CPDirectionsCheckBox->Checked, CPEditArrRange->Text.ToInt(), CPEditDepRange->Text.ToInt()))
15129  {
15130  ShowMessage("Analysis complete and file created");
15131  }
15132  ConflictPanel->Visible = false;
15133  }
15134  }
15135  Screen->Cursor = TCursor(-2); // arrow
15136  Utilities->CallLogPop(2222);
15137  }
15138  catch(const Exception &e)
15139  {
15140  ErrorLog(219, e.Message);
15141  }
15142 }
15143 
15144 // ---------------------------------------------------------------------------
15145 
15146 void __fastcall TInterface::ReloadConfigMenuItemClick(TObject *Sender) //new for v2.11.0
15147 {
15148  try
15149  {
15150  TrainController->LogEvent("ReloadConfigMenuItemClick");
15151  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReloadConfigMenuItemClick");
15152  LoadConfigFile(1, false); //false as it's not the first load
15153  Utilities->CallLogPop(2401);
15154  }
15155  catch(const Exception &e)
15156  {
15157  ErrorLog(238, e.Message);
15158  }
15159 }
15160 
15161 // ---------------------------------------------------------------------------
15162 
15163 void TInterface::LoadConfigFile(int Caller, bool FirstLoad)
15164 {
15165  try
15166  {
15167  //throw Exception(""); to test error message
15168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadConfigFile," + AnsiString((unsigned char)FirstLoad));
15169  int LengthInt, SpeedInt;
15170  std::ifstream ConfigFile((CurDir + "\\Config.txt").c_str()); // added at v2.6.0 to set save & load directories for railways, timetables & session & to
15171  if(ConfigFile.fail()) // no Config file //replace Signal.hnd, Background.col and GNU
15172  {
15173  if(FirstLoad) //added atv2.11.0 - may have changed to RH sigs so don't want it resetting to left when load a railway or session
15174  {
15175  ConvertToOtherHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
15176  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
15177  SigsOnLeftImage1->Visible = true;
15178  SigsOnLeftImage2->Visible = true;
15179  SigsOnRightImage1->Visible = false;
15180  SigsOnRightImage2->Visible = false;
15181  ShowMessage(
15182  "This program is free software released under the terms of the GNU General Public License Version 3, as published by the Free Software Foundation. "
15183  " It may be used or redistributed in accordance with that license and is released in the hope that it will be useful, but WITHOUT ANY WARRANTY; "
15184  "without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details - "
15185  "you should have received a copy along with this program but if not see <http://www.gnu.org/licenses/>.");
15186  }
15187  }
15188  else
15189  {
15190  AnsiString ConfigStr = "";
15191  bool ContinueFlag = false;
15192  do
15193  {
15194  if(Utilities->CheckAndReadOneLineFromConfigFile(ConfigFile, ConfigStr))
15195  {
15196  if(ConfigFile.eof())
15197  {
15198  break;
15199  }
15200  //changes at v2.11.0 to add default track lengths and speeds (for user editing) and to add comments
15201  // AnsiString ConfigValue = ConfigStr.SubString(9, ConfigStr.Length() - 8);
15202  if(ConfigStr == "")
15203  {
15204  continue; //ignore blank lines
15205  }
15206  if(ConfigStr[1] == '#')
15207  {
15208  continue; //ignore lines thet begin with ''#'
15209  }
15210  for(int x = 1; x <= ConfigStr.Length(); x++)
15211  {
15212  if(ConfigStr[x] == '#')
15213  {
15214  ConfigStr = ConfigStr.SubString(1, x - 1); //strip the '#' and all after it
15215  //get rid of all spaces & tabs at end of text (Trim() doesn't remove tabs)
15216  while((ConfigStr.SubString(ConfigStr.Length(), 1) == AnsiString(' ')) || (ConfigStr.SubString(ConfigStr.Length(), 1) == AnsiString('\t')))
15217  {
15218  ConfigStr = ConfigStr.SubString(1, ConfigStr.Length() - 1);
15219  }
15220  break;
15221  }
15222  }
15223  AnsiString ConfigValue = ConfigStr.SubString(9, ConfigStr.Length() - 8);
15224  if((ConfigStr.SubString(1, 8) == "Signals=") && FirstLoad)
15225  {
15226  //get rid of all spaces & tabs at beginning of text
15227  while((ConfigValue.SubString(1, 1) == AnsiString(' ')) || (ConfigValue.SubString(1, 1) == AnsiString('\t')))
15228  {
15229  ConfigValue = ConfigValue.SubString(2, ConfigValue.Length() - 1);
15230  }
15231  if((ConfigValue == "right") && !Utilities->RHSignalFlag)
15232  {
15233  RailGraphics->ConvertSignalsToOppositeHand(1); // toggles Utilities->RHSignalFlag in function (sigs always left hand on startup)
15234  ConvertToOtherHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
15236  {
15238  }
15239  else
15240  {
15242  }
15243  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
15244  SigsOnLeftImage1->Visible = false;
15245  SigsOnLeftImage2->Visible = false;
15246  SigsOnRightImage1->Visible = true;
15247  SigsOnRightImage2->Visible = true;
15248  }
15249  else if((ConfigValue == "left") && Utilities->RHSignalFlag)
15250  {
15251  RailGraphics->ConvertSignalsToOppositeHand(2); // toggles Utilities->RHSignalFlag in function
15252  ConvertToOtherHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
15254  {
15256  }
15257  else
15258  {
15260  }
15261  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
15262  SigsOnLeftImage1->Visible = true;
15263  SigsOnLeftImage2->Visible = true;
15264  SigsOnRightImage1->Visible = false;
15265  SigsOnRightImage2->Visible = false;
15266  } //if not either of these then sigs already set as should be
15267  }
15268  if((ConfigStr.SubString(1, 8) == "BgndCol=") && FirstLoad)
15269  {
15270  // pick up transparent colour from file if there is one & set it to the stored value if it's valid else set to black
15271  Utilities->clTransparent = clB0G0R0; // default black background;
15272  if(ConfigValue == "white")
15273  {
15274  Utilities->clTransparent = TColor(0xFFFFFF);
15275  }
15276  else if(ConfigValue == "blue")
15277  {
15278  Utilities->clTransparent = TColor(0x330000);
15279  }
15280  }
15281  if((ConfigStr.SubString(1, 8) == "RLYLocn=") && FirstLoad)
15282  {
15283  if(DirectoryExists(ConfigValue)) // else stays as original directory
15284  {
15285  SaveRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
15286  LoadRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
15287  }
15288  }
15289  else if((ConfigStr.SubString(1, 8) == "TTBLocn=") && FirstLoad)
15290  {
15291  if(DirectoryExists(ConfigValue)) // else stays as original directory
15292  {
15293  TimetableDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
15294  SaveTTDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
15295  }
15296  }
15297  else if((ConfigStr.SubString(1, 8) == "SSNLocn=") && FirstLoad)
15298  {
15299  if(DirectoryExists(ConfigValue)) // else stays as original directory
15300  {
15301  LoadSessionDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
15302  }
15303  }
15304  else if(ConfigStr.SubString(1, 8) == "Length =")
15305  {
15306  for(int x = 1; x <= ConfigValue.Length(); x++)
15307  {
15308  if((ConfigValue[x] < '0') || (ConfigValue[x] > '9'))
15309  {
15310  ContinueFlag = true; //ignore it if invalid
15311  break;
15312  }
15313  }
15314  if(ContinueFlag)
15315  {
15316  ContinueFlag = false;
15317  continue;
15318  }
15319  LengthInt = ConfigStr.SubString(9, ConfigStr.Length() - 8).ToInt();
15320  if(LengthInt < 10)
15321  {
15322  Track->DefaultTrackLength = 10;
15323  }
15324  if(LengthInt > 99999)
15325  {
15326  Track->DefaultTrackLength = 100;
15327  }
15328  else
15329  {
15330  Track->DefaultTrackLength = LengthInt;
15331  }
15332  }
15333  else if(ConfigStr.SubString(1, 8) == "Speed =")
15334  {
15335  for(int x = 1; x <= ConfigValue.Length(); x++)
15336  {
15337  if((ConfigValue[x] < '0') || (ConfigValue[x] > '9'))
15338  {
15339  ContinueFlag = true; //ignore it if invalid
15340  break;
15341  }
15342  }
15343  if(ContinueFlag)
15344  {
15345  ContinueFlag = false;
15346  continue;
15347  }
15348  SpeedInt = ConfigStr.SubString(9, ConfigStr.Length() - 8).ToInt();
15349  if(SpeedInt < 10)
15350  {
15352  }
15353  else if(SpeedInt > 400)
15354  {
15356  }
15357  else
15358  {
15359  Track->DefaultTrackSpeedLimit = SpeedInt;
15360  }
15361  }
15362  }
15363  else
15364  {
15365  break;
15366  }
15367  }
15368  while(!ConfigFile.eof());
15369  ConfigFile.close();
15370  Utilities->CallLogPop(2402);
15371  }
15372  }
15373  catch(const Exception &e)
15374  {
15375  ShowMessage("Unable to load the configuration file, it appears to be corrupt. It will be re-written correctly when the program closes.\n\n"
15376  "Default values will be used for the current session.");
15377  Utilities->RHSignalFlag = false;
15378  ConvertToOtherHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
15379  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
15380  SigsOnLeftImage1->Visible = true;
15381  SigsOnLeftImage2->Visible = true;
15382  SigsOnRightImage1->Visible = false;
15383  SigsOnRightImage2->Visible = false;
15384  Utilities->clTransparent = clB0G0R0; // default black background;
15385  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
15386  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
15387  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
15388  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
15389  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
15390  Track->DefaultTrackLength = 100;
15392  }
15393 }
15394 
15395 //---------------------------------------------------------------------------
15396 
15398 {
15399  try
15400  {
15401  TrainController->LogEvent("SaveConfigFile");
15402  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveConfigFile");
15403  // rewrite ConfigFile with signal handedness, background colour & InitialDir values (may be same but no matter)
15404  AnsiString ColourStr = "", SignalStr = "", LengthStr = "", SpeedStr = "";
15405  remove((CurDir + "\\Config.txt").c_str());
15406  std::ofstream ConfigFile((CurDir + "\\Config.txt").c_str());
15407  ColourStr = "black";
15408  SignalStr = "left";
15409  if((Track->DefaultTrackLength < 10) || (Track->DefaultTrackLength > 99999))
15410  {
15411  Track->DefaultTrackLength = 100;
15412  }
15414  {
15416  }
15417  LengthStr = AnsiString(Track->DefaultTrackLength);
15418  SpeedStr = AnsiString(Track->DefaultTrackSpeedLimit);
15419  if(Utilities->clTransparent == TColor(0xFFFFFF))
15420  {
15421  ColourStr = "white";
15422  }
15423  else if(Utilities->clTransparent == TColor(0x330000))
15424  {
15425  ColourStr = "blue";
15426  }
15427  if(Utilities->RHSignalFlag)
15428  {
15429  SignalStr = "right";
15430  }
15431  ConfigFile << AnsiString("#This file contains a list of parameters that are saved after each use of the program and reloaded for the "
15432  "next use. Track element length and speed limit values after the = sign may be changed and the configuration file reloaded "
15433  "during play, but please do not change anything else. Comments begin with '#' and are ignored by the program.\n\n");
15434  ConfigFile << AnsiString("Signals=") << SignalStr << '\n';
15435  ConfigFile << AnsiString("BgndCol=") << ColourStr << '\n';
15436  ConfigFile << AnsiString("RLYLocn=") << AnsiString(LoadRailwayDialog->InitialDir) << '\n';
15437  ConfigFile << AnsiString("TTBLocn=") << AnsiString(TimetableDialog->InitialDir) << '\n';
15438  ConfigFile << AnsiString("SSNLocn=") << AnsiString(LoadSessionDialog->InitialDir) << '\n';
15439  ConfigFile << AnsiString("Length =") << LengthStr << " #default track element length in metres (not less than 10)\n";
15440  ConfigFile << AnsiString("Speed =") << SpeedStr << " #default track element speed limit in km/h (not less than 10 and not greater than 400)\n";
15441  ConfigFile.close();
15442  Utilities->CallLogPop(2439);
15443  }
15444  catch(const Exception &e)
15445  {
15446  ShowMessage("Unable to save configuration file, file won't be updated");
15447  }
15448 }
15449 
15450 // ---------------------------------------------------------------------------
15451 
15452 void TInterface::SetTopIndex(int Caller)
15453 {
15454 // Set TopIndex to the proper value & also Selected so don't have a different selection to the highlighted entry
15455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTopIndex");
15456  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty()) //added at v2.13.0 as a fix for mathstrains19 (discord name) error reported 13/04/22
15457  { //without this it crashes at line before last with "List index out of bounds"
15458  Utilities->CallLogPop(2485);
15459  return;
15460  }
15461  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < AllEntriesTTListBox->TopIndex)
15462  {
15464  }
15465  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (AllEntriesTTListBox->TopIndex + 45))
15466  {
15467  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
15468  }
15469  else //leave AllEntriesTTListBox->TopIndex as it is
15470  {
15471 // AllEntriesTTListBox->TopIndex = AllEntriesTTListBox->TopIndex; //removed at v2.13.0 as serves no purpose
15472  }
15473  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
15474  Utilities->CallLogPop(2207);
15475 }
15476 
15477 // ---------------------------------------------------------------------------
15478 
15479 void TInterface::ClearandRebuildRailway(int Caller) // now uses HiddenScreen to help avoid flicker
15480 {
15481  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearandRebuildRailway");
15482  bool ClockState = Utilities->Clock2Stopped;
15483 
15484  Utilities->Clock2Stopped = true;
15486  Track->RebuildUserGraphics(0, HiddenDisplay); // new at v2.4.0, plot first so all else overwrites, including the grid if selected
15487  if(ScreenGridFlag && (Level1Mode == TrackMode))
15488  {
15489  int WidthNum = int(MainScreen->Width / 160) + 1;
15490  int HeightNum = int(MainScreen->Height / 144) + 1;
15491  for(int x = 0; x < WidthNum; x++)
15492  {
15493  for(int y = 0; y < HeightNum; y++)
15494  {
15495  HiddenDisplay->PlotAbsolute(0, x * 160, y * 144, RailGraphics->GridBitmap);
15496  }
15497  }
15498  }
15499 // TextHandler->RebuildFromTextVector(1, HiddenDisplay); //This now incorporated in RebuildTrackAndText so that text is plotted after inactive
15500 // elements but before active elements. This is so text can overwite stations and non-station named locations.
15501 
15503 
15504 // Display->Output->Invalidate(); experiment, needs TDisplay Output to be public. Trying to invoke the white flashes that
15505 // used to occur frequently without Disp->Update() in PlotOriginal
15506 
15507  // OperMode LCs plotted below
15509  {
15511  }
15512  if(Level1Mode == PrefDirMode)
15513  {
15514  if(EveryPrefDir->PrefDirSize() > 0)
15515  {
15517  }
15519  {
15521  }
15522  }
15523  if(Level1Mode == TrackMode)
15524  {
15526  {
15527  LocationNameButton->Enabled = true;
15528  }
15529  else
15530  {
15531  LocationNameButton->Enabled = false;
15532  }
15533  }
15535  {
15537  DistanceKey->Visible = true;
15538  DistancesMarked = true;
15539  LengthConversionPanel->Visible = true;
15540  SpeedConversionPanel->Visible = true;
15541  }
15542  if(Level2TrackMode == DistanceContinuing) // for extended distances
15543  {
15544  if(ConstructPrefDir->PrefDirSize() > 0)
15545  {
15547 // this line was after the next line until v2.5.1, changed so magenta not overrridden after PrefDirMarker called
15549  DistanceKey->Visible = true;
15550  DistancesMarked = true;
15551  LengthConversionPanel->Visible = true;
15552  SpeedConversionPanel->Visible = true;
15553  }
15554  }
15556  // this is to keep the distance markers if they are already present when Select is chosen, in case user wishes to choose SelectLengths,
15557  // don't need to display ConstructPrefDir marker as that only needed in DistanceContinuing mode
15558  {
15560  DistanceKey->Visible = true;
15561  }
15563  // cancel DistancesMarked if exit from any of these modes
15564  {
15565  DistancesMarked = false;
15566  DistanceKey->Visible = false;
15567  LengthConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
15568  SpeedConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
15569  }
15571  // in process of moving so use NewSelectBitmapHLoc & VLoc
15572  {
15574  }
15575 
15577  // not in process of moving or failed to click mouse within selection so use SelectBitmapHLoc & VLoc
15578  {
15580  }
15581  if(Level1Mode == OperMode)
15582  {
15584  if(!AllRoutes->LockedRouteVector.empty())
15585  {
15586  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
15587  {
15588  if(!(AllRoutes->TrackIsInARoute(7, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos)))
15589  {
15590  AllRoutes->LockedRouteVector.erase(LRVIT);
15591  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
15592  // hence no longer needed so get rid of it (end of route can't be points, crossover or bridge so danger of
15593  // route being on the other track of a 2-track element doesn't arise)
15594  continue;
15595  }
15596  TOneRoute Route = AllRoutes->GetFixedRouteAt(0, LRVIT->RouteNumber);
15597  int x = Route.PrefDirSize() - 1;
15598  bool BreakFlag = false;
15599  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(1, x);
15600  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
15601  {
15602  HiddenDisplay->PlotOutput(10, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
15603  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
15604  if(!(AllRoutes->TrackIsInARoute(8, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
15605  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
15606  {
15607  BreakFlag = true;
15608  break; // train removed earlier element from route so stop here
15609  }
15610  x--;
15611  if(x < 0) // added after Albie Vowles reported error on 14/08/20 by email
15612  {
15613  // it means that part of the route (including that at the truncate point) has been cancelled, in this case by a train running past the signal
15614  BreakFlag = true;
15615 // at danger and cancelling the route elements in front of it. The locked route is now too short and this 'while' loop won't find
15616  break; // it, so x keeps decrementing and when it becomes -1 an error is thrown. This addition prevents the error.
15617  }
15618  PrefDirElement = Route.GetFixedPrefDirElementAt(2, x);
15619  }
15620  if(!BreakFlag)
15621  {
15622  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
15623  {
15624  HiddenDisplay->PlotOutput(11, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
15625  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
15626  }
15627  }
15628  }
15629  }
15630  if(RouteMode == RouteContinuing)
15631  {
15633 // system thinks overlay is already plotted, so plot original to reset the OverlayPlotted flag
15636  if(AutoSigsFlag)
15637  {
15639  }
15640  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
15641  {
15643  }
15644  else
15645  {
15647  }
15648  }
15649  if(Track->PointFlashFlag)
15650  {
15651  // need to reset the screen location for picking up the original graphic
15652  int Left, Top; // Embarcadero change - these missing in error from Borland file
15654  // note that the above Pos values are wrt layout, not the screen, but the Left & Top values are wrt screen
15655  PointFlash->SetSourceRect(Left, Top);
15656  PointFlash->LoadOriginalScreenGraphic(4); // reload from new position
15657  // doesn't matter whether Flash was on or off when this function called as will sort itself out later (may miss a flash but won't be noticeable)
15658  }
15659  // now plot level crossings (must be after routes). These don't need any base elements to be plotted as they are already plotted.
15660  // In order to avoid plotting the whole LC for every element of a LC a bool value - LCPlotted - is used to save time
15661  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
15662  {
15663  (Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)))->LCPlotted = false;
15664  }
15665  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
15666  {
15667  int BaseSpeedTag;
15668  TTrackElement ATE;
15669  TTrackElement ITE = *(Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)));
15670  {
15671  BaseSpeedTag = Track->GetTrackElementFromTrackMap(0, ITE.HLoc, ITE.VLoc).SpeedTag;
15672  if(ITE.LCPlotted == false)
15673  {
15674  if(ITE.Attribute == 0)
15675  {
15677  }
15678  else if(ITE.Attribute == 1)
15679  {
15680  // need to determine if should plot green (manual) or red (auto), but all linked LCs have ConsecSignals set to 2 in BarriersDownVector if manual
15681  // so just need to test this for the HLoc & VLoc position match
15682  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
15683  {
15684  if((Track->BarriersDownVector.at(x).HLoc == ITE.HLoc) && (Track->BarriersDownVector.at(x).VLoc == ITE.VLoc))
15685  {
15686  if(Track->BarriersDownVector.at(x).TypeOfRoute == 2)
15687  {
15689  true); // true for manual = green
15690  }
15691  else
15692  {
15694  false); // false for auto = red
15695  }
15696  }
15697  }
15698  }
15699  // if ITE->Attribute == 2 then LC is changing, FlashingGraphics will take care of flashing & final plotting,
15700  // it won't set LCPlotted but no real time lost in this case
15701  }
15702  }
15703  }
15705  }
15706  Display->ZoomOutFlag = false;
15707  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomOut");
15708  MainScreen->Picture->Bitmap->Assign(HiddenScreen->Picture->Bitmap);
15709  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
15710  Utilities->Clock2Stopped = ClockState;
15711  Utilities->CallLogPop(91);
15712 }
15713 
15714 // ---------------------------------------------------------------------------
15715 
15716 bool TInterface::HighLightOneGap(int Caller, int &HLoc, int &VLoc)
15717 {
15718  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighLightOneGap");
15719  if(Track->FindAndHighlightAnUnsetGap(1)) // true if find one
15720  {
15721  if(!PreventGapOffsetResetting) // don't reset display position if returning from zoomout mode
15722  {
15723  while((Display->DisplayOffsetH - Track->GetGapHLoc()) > 0)
15724  {
15725  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
15726  }
15728  {
15730  }
15731  while((Display->DisplayOffsetV - Track->GetGapVLoc()) > 0)
15732  {
15733  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
15734  }
15736  {
15738  }
15739  }
15740  InfoPanel->Visible = true;
15741  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting element";
15742  ClearandRebuildRailway(31); // get rid of earlier gap selection
15743  Utilities->CallLogPop(92);
15744  return(true); // return as one now identified & over to MainScreenMouseDown with Level2TrackMode = GapSetting
15745  }
15746  Utilities->CallLogPop(93);
15747  return(false); // no unset ones left to find
15748 }
15749 
15750 // ---------------------------------------------------------------------------
15751 
15753 {
15754  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearEverything");
15755  if(FileChangedFlag)
15756  {
15757  UnicodeString MessageStr = "The railway has changed, close it without saving?";
15758  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
15759  if(button == IDNO)
15760  {
15761  Utilities->CallLogPop(1140);
15762  return(false);
15763  }
15764  }
15765  Display->ClearDisplay(7);
15767 
15768  Display->DisplayOffsetH = 0;
15769  Display->DisplayOffsetV = 0;
15774 
15775 // these ensure that all persistent vectors, maps & multimaps etc are cleared
15776  delete TrainController;
15777  delete EveryPrefDir;
15778  delete SelectPrefDir;
15779  delete ConstructRoute;
15780  delete ConstructPrefDir;
15781  delete AllRoutes;
15782  delete Track;
15783  delete TextHandler;
15784 // NB can't delete & recreate Utilities or will lose the CallLog file & have errors due to log being empty when try to
15785 // pop earlier pushed values
15786 // OK though as no containers in Utilities that need to clear & PerformanceFile recreated when begin to operate a later
15787 // railway
15788  TextHandler = new TTextHandler;
15789  Track = new TTrack;
15790  AllRoutes = new TAllRoutes;
15792  ConstructRoute = new TOneRoute;
15793  EveryPrefDir = new TOnePrefDir;
15794  SelectPrefDir = new TOnePrefDir;
15796  PerformanceLogBox->Lines->Clear();
15797  ResetAll(1);
15798 
15799  LoadConfigFile(2, false); //reset default track element length & speed limit (uninitialised when Track recreated), false as it's not the first load
15800 
15801  Utilities->CallLogPop(94);
15802  return(true);
15803 }
15804 
15805 // ---------------------------------------------------------------------------
15806 
15807 bool TInterface::FileIntegrityCheck(int Caller, char *FileName) const // true for success
15808 {
15809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FileIntegrityCheck," + AnsiString(FileName));
15810  std::ifstream VecFile(FileName);
15811 
15812  if(VecFile.is_open())
15813  {
15814  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // Program version
15815  {
15816  VecFile.close();
15817  Utilities->CallLogPop(1805);
15818  return(false);
15819  }
15820  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetHHome
15821  {
15822  VecFile.close();
15823  Utilities->CallLogPop(1440);
15824  return(false);
15825  }
15826  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetVHome
15827  {
15828  VecFile.close();
15829  Utilities->CallLogPop(1441);
15830  return(false);
15831  }
15832  bool GraphicsFollow = false;
15833  int NumberOfActiveElements;
15834  if(!(Track->CheckTrackElementsInFile(1, NumberOfActiveElements, GraphicsFollow, VecFile))) // for new loads
15835  {
15836  VecFile.close();
15837  Utilities->CallLogPop(95);
15838  return(false);
15839  }
15840  if(!(TextHandler->CheckTextElementsInFile(0, VecFile)))
15841  {
15842  VecFile.close();
15843  Utilities->CallLogPop(96);
15844  return(false);
15845  }
15846  if(!(EveryPrefDir->CheckOnePrefDir(0, NumberOfActiveElements, VecFile)))
15847  {
15848  VecFile.close();
15849  Utilities->CallLogPop(97);
15850  return(false);
15851  }
15852  if(GraphicsFollow)
15853  {
15854  if(!Track->CheckUserGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
15855  {
15856  VecFile.close();
15857  Utilities->CallLogPop(2186);
15858  return(false);
15859  }
15860  }
15861  VecFile.close();
15862  }
15863  else
15864  {
15865  Utilities->CallLogPop(1153);
15866  return(false);
15867  }
15868  Utilities->CallLogPop(98);
15869  return(true);
15870 }
15871 
15872 // ---------------------------------------------------------------------------
15873 
15874 void TInterface::Delay(int Caller, double Msec)
15875 {
15876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Delay," + AnsiString(Msec));
15877  TDateTime First, Second;
15878  bool Finished = false;
15879 
15880  First = TDateTime::CurrentDateTime();
15881  double TimeVal1 = 86400000 * double(First); // no of msec in a day
15882 
15883  while(!Finished)
15884  {
15885  Second = TDateTime::CurrentDateTime();
15886  double TimeVal2 = 86400000 * double(Second);
15887  if((TimeVal2 - TimeVal1) > Msec)
15888  {
15889  Finished = true;
15890  }
15891  }
15892  Utilities->CallLogPop(1203);
15893 }
15894 
15895 // ---------------------------------------------------------------------------
15896 
15898 {
15899  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetCurrentSpeedButton");
15900  if(CurrentSpeedButton)
15901  {
15902  CurrentSpeedButton->Down = false;
15903  }
15904  CurrentSpeedButton = 0;
15905  Utilities->CallLogPop(1204);
15906 }
15907 
15908 // ---------------------------------------------------------------------------
15909 
15911 {
15912  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MovingTrainPresentOnFlashingRoute");
15913  int TrainID;
15914 
15915  if(ConstructRoute->SearchVectorSize() == 0)
15916  {
15917  Utilities->CallLogPop(99);
15918  return(false);
15919  }
15920  for(unsigned int x = 0; x < ConstructRoute->SearchVectorSize(); x++)
15921  {
15922  TPrefDirElement PrefDirElement = ConstructRoute->GetFixedSearchElementAt(14, x);
15923  if(PrefDirElement.TrackType == Bridge)
15924  {
15925  if(PrefDirElement.GetXLinkPos() < 2)
15926  {
15927  TrainID = Track->TrackElementAt(486, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos01;
15928  }
15929  else
15930  {
15931  TrainID = Track->TrackElementAt(487, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos23;
15932  }
15933  }
15934  else
15935  {
15936  TrainID = Track->TrackElementAt(488, PrefDirElement.GetTrackVectorPosition()).TrainIDOnElement;
15937  }
15938  if((TrainID > -1) && !(TrainController->TrainVectorAtIdent(4, TrainID).Stopped()))
15939  {
15940  Utilities->CallLogPop(100);
15941  return(true);
15942  }
15943  // check for crossed diagonal fouling by train added at v1.2.0
15944  int TrainID; // not used
15945  int LinkNumber1 = PrefDirElement.Link[PrefDirElement.GetELinkPos()];
15946  int LinkNumber2 = PrefDirElement.Link[PrefDirElement.GetXLinkPos()];
15947  if((LinkNumber1 == 1) || (LinkNumber1 == 3) || (LinkNumber1 == 7) || (LinkNumber1 == 9))
15948  {
15949  if(Track->DiagonalFouledByTrain(1, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber1, TrainID))
15950  {
15951  Utilities->CallLogPop(2037);
15952  return(true);
15953  }
15954  }
15955  if((LinkNumber2 == 1) || (LinkNumber2 == 3) || (LinkNumber2 == 7) || (LinkNumber2 == 9))
15956  {
15957  if(Track->DiagonalFouledByTrain(2, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber2, TrainID))
15958  {
15959  Utilities->CallLogPop(2038);
15960  return(true);
15961  }
15962  }
15963  }
15964  Utilities->CallLogPop(101);
15965  return(false);
15966 }
15967 
15968 // ---------------------------------------------------------------------------
15969 
15971 {
15972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RevertToOriginalRouteSelector");
15973  AutoRouteStartMarker->PlotOriginal(26, Display); // if overlay not plotted will ignore
15974  SigRouteStartMarker->PlotOriginal(27, Display); // if overlay not plotted will ignore
15975  NonSigRouteStartMarker->PlotOriginal(28, Display); // if overlay not plotted will ignore
15976  RouteCancelFlag = false;
15978  {
15979  RouteCancelButton->Enabled = true;
15980  }
15981  else
15982  {
15983  RouteCancelButton->Enabled = false;
15984  }
15987 // reset here so that a n element that has been selected and then not doesn't remain set as a single element
15988  InfoPanel->Visible = true;
15989  if(Level2OperMode != Paused)
15990  {
15991  InfoPanel->Caption = InfoCaptionStore;
15992  }
15993  Utilities->CallLogPop(102);
15994 }
15995 
15996 // ---------------------------------------------------------------------------
15997 
15998 // usermode functions below
16000 {
16001  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel1Mode");
16002  if(!Display->ZoomOutFlag)
16003  {
16006  Track->GapFlashFlag = false;
16007  }
16008 // GapFlash resets when any mode selected unless zoomed out
16009 // note that if selecting zoom back in then this will be called before ZoomOutFlag is reset so won't
16010 // reset GapFlashFlag
16011  switch(Level1Mode) // use the data member
16012  {
16013  case BaseMode:
16014  CopyMenuItem->ShortCut = TextToShortCut(""); // added these for v2.1.0 to set default values after use of the 'Edit' menu during track building
16015  CutMenuItem->ShortCut = TextToShortCut(""); // to allow normal cutting/copying/pasting, especially in timetable construction or editing
16016  PasteMenuItem->ShortCut = TextToShortCut("");
16021  LengthConversionPanel->Visible = false;
16022  SpeedConversionPanel->Visible = false;
16023  TimetableEditPanel->Visible = false;
16024  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
16025  TrackBuildPanel->Visible = false;
16026  TrackElementPanel->Visible = false;
16027  LocationNameTextBox->Visible = false;
16028  TextBox->Visible = false;
16029  TrackLengthPanel->Visible = false;
16030  InfoPanel->Visible = false;
16031  PrefDirPanel->Visible = false;
16032  TimetablePanel->Visible = false;
16033  OperatingPanel->Visible = false;
16034  PrefDirKey->Visible = false;
16035  TrackLinkedImage->Visible = false;
16036  TrackNotLinkedImage->Visible = false;
16037  GapsSetImage->Visible = false;
16038  GapsNotSetImage->Visible = false;
16039  LocationNamesSetImage->Visible = false;
16040  LocationNamesNotSetImage->Visible = false;
16041  ModeMenu->Enabled = true;
16042  FileMenu->Enabled = true;
16043  EditMenu->Enabled = false;
16044  BuildTrackMenuItem->Enabled = true;
16045  MultiplayerMenu->Enabled = false;
16046  CouplingFileLoadedFlag = false;
16048  PlayerReadyToBeginFlag = false;
16049  PlayerCancelJoinFlag = false;
16051  HostInSessionFlag = false;
16052  PlayerInSessionFlag = false;
16053  SigAspectButton->Enabled = false;
16054  Track->ChangingLCVector.clear();
16055  Track->BarriersDownVector.clear();
16057  ConvertToOtherHandSignalsMenuItem->Enabled = false; // new at v2.3.0
16058  SigImagePanel->Visible = false; // new at v2.3.0
16059  MTBFEditBox->Visible = false; // new at v2.4.0
16060  MTBFLabel->Visible = false;
16061  TTClockAdjustWarningPanel->Visible = false;
16063  DelayMenu->Visible = false; //added at v2.13.0
16064  DelayMenu->Enabled = false;
16065  if(Track->IsTrackFinished())
16066  {
16067  PlanPrefDirsMenuItem->Enabled = true;
16068  if(TimetableTitle != "")
16069  {
16070  OperateRailwayMenuItem->Enabled = true;
16071  }
16072  else
16073  {
16074  OperateRailwayMenuItem->Enabled = false;
16075  }
16076  }
16077  else
16078  {
16079  PlanPrefDirsMenuItem->Enabled = false;
16080  OperateRailwayMenuItem->Enabled = false;
16081  }
16082  if(RlyFile)
16083  {
16084  LoadTimetableMenuItem->Enabled = true;
16085  }
16086  else
16087  {
16088  LoadTimetableMenuItem->Enabled = false;
16089  }
16090  LoadRailwayMenuItem->Enabled = true;
16091  if(NoRailway())
16092  {
16093  SaveAsMenuItem->Enabled = false;
16094  ImageMenu->Enabled = false;
16095  SaveImageAndGridMenuItem->Enabled = false;
16096  SaveImageNoGridMenuItem->Enabled = false;
16097  SaveImageAndPrefDirsMenuItem->Enabled = false;
16098  SaveOperatingImageMenuItem->Enabled = false;
16099  BlackBgndMenuItem->Enabled = false;
16100  WhiteBgndMenuItem->Enabled = false;
16101  BlueBgndMenuItem->Enabled = false;
16102  ConvertToOtherHandSignalsMenuItem->Enabled = true; // new at v2.3.0
16103  SigImagePanel->Visible = true; // new at v2.3.0
16104  if(Utilities->clTransparent != TColor(0))
16105  {
16106  BlackBgndMenuItem->Enabled = true;
16107  }
16108  if(Utilities->clTransparent != TColor(0xFFFFFF))
16109  {
16110  WhiteBgndMenuItem->Enabled = true;
16111  }
16112  if(Utilities->clTransparent != TColor(0x330000))
16113  {
16114  BlueBgndMenuItem->Enabled = true;
16115  }
16116  ClearAllMenuItem->Enabled = false;
16117  InfoPanel->Visible = true;
16118  InfoPanel->Caption = "Select an option from the File, Mode or Help menus";
16119  }
16120  else
16121  {
16122  InfoPanel->Visible = false;
16123  SaveAsMenuItem->Enabled = true;
16124  ImageMenu->Enabled = true;
16125  SaveImageAndGridMenuItem->Enabled = true;
16126  SaveImageNoGridMenuItem->Enabled = true;
16127  if(EveryPrefDir->PrefDirSize() > 0)
16128  {
16129  SaveImageAndPrefDirsMenuItem->Enabled = true;
16130  }
16131  else
16132  {
16133  SaveImageAndPrefDirsMenuItem->Enabled = false;
16134  }
16135  BlackBgndMenuItem->Enabled = false;
16136  WhiteBgndMenuItem->Enabled = false;
16137  BlueBgndMenuItem->Enabled = false;
16138  SaveOperatingImageMenuItem->Enabled = false;
16139  ClearAllMenuItem->Enabled = true;
16140  }
16141  if(SavedFileName == "")
16142  {
16143  SaveMenuItem->Enabled = false;
16144  }
16145  else if(!FileChangedFlag)
16146  {
16147  SaveMenuItem->Enabled = false;
16148  }
16149  else if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
16150  {
16151  if(!(Track->IsReadyForOperation(false)))
16152  {
16153  SaveMenuItem->Enabled = false; // can't save under its old name as not now a .rly file
16154  }
16155  else
16156  {
16157  SaveMenuItem->Enabled = true; // must have changed some of the PrefDirs (because FileChangedFlag is true)
16158  }
16159  }
16160  else
16161  {
16162  SaveMenuItem->Enabled = true;
16163  }
16164  LoadSessionMenuItem->Enabled = true;
16165  ExitMenuItem->Enabled = true;
16166  ScreenGridFlag = false;
16167  TrainController->CrashWarning = false;
16168  TrainController->DerailWarning = false;
16169  TrainController->SPADWarning = false;
16171  TrainController->CallOnWarning = false;
16174  UserGraphicReselectPanel->Visible = false;
16175  ClearandRebuildRailway(32); // to get rid of unwanted displays (eg distance markers)
16176  SetTrackBuildImages(13);
16177  ClipboardChecked = false;
16178  Utilities->CumulativeDelayedRandMinsAllTrains = 0; //added at v2.13.0
16179  break;
16180 
16181  case TimetableMode:
16182  if(TwoLocationNamePanel->Visible) //added at v2.9.1 so panel persists until button clicked
16183  {
16184  break;
16185  }
16189  ModeMenu->Enabled = false;
16190  SigImagePanel->Visible = false; // new at v2.3.0
16191  FileMenu->Enabled = false;
16192  EditMenu->Enabled = false;
16193  FloatingInfoMenu->Enabled = false;
16194  ImageMenu->Enabled = false;
16195  TimetableEditPanel->BringToFront();
16196  TimetableHandler();
16197  break;
16198 
16199  case TrackMode:
16200  {
16201  if(Level2TrackMode == CutMoving)
16202  {
16203  Level2TrackMode = Pasting; // paste the selection
16204  SetLevel2TrackMode(52); // CancelSelectionFlag used in Case Pasting
16205  }
16210  TrackBuildPanel->Visible = true;
16211  TrackBuildPanelLabel->Caption = "Build/modify";
16212  TrackElementPanel->Visible = false;
16213  TrackLengthPanel->Visible = false;
16214  PrefDirPanel->Visible = false;
16215  TimetablePanel->Visible = false;
16216  OperatingPanel->Visible = false;
16217  InfoPanel->Visible = false;
16218  InfoPanel->Caption = "";
16219  LocationNameTextBox->Visible = false;
16220  TextBox->Visible = false;
16221  ModeMenu->Enabled = false;
16222  SigImagePanel->Visible = false; // new at v2.3.0
16223  FileMenu->Enabled = false;
16224  // set edit menu items
16226  // display track buttons
16227  AddTrackButton->Enabled = true;
16229  {
16230  LocationNameButton->Enabled = true;
16231  }
16232  else
16233  {
16234  LocationNameButton->Enabled = false;
16235  }
16236  ScreenGridButton->Enabled = true;
16237  ExitTrackButton->Enabled = true;
16238  SetGapsButton->Enabled = false;
16239  TrackOKButton->Enabled = false;
16240  if(Track->GapsUnset(5))
16241  {
16242  SetGapsButton->Enabled = true;
16243  }
16244  // only enable if there are gaps still to be set (returns false for no track)
16245  else
16246  {
16247  if(!(Track->NoActiveTrack(2)) && !(Track->IsTrackFinished()))
16248  {
16249  TrackOKButton->Enabled = true;
16250  }
16251  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
16252  }
16253  SetLengthsButton->Enabled = false;
16254  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
16255  {
16256  SetLengthsButton->Enabled = true;
16257  }
16258  // text buttons
16259  AddTextButton->Enabled = true;
16260  TextOrUserGraphicGridButton->Enabled = true;
16261  FontButton->Enabled = true;
16262  MoveTextOrGraphicButton->Enabled = false;
16263  if(TextHandler->TextVectorSize(9) > 0)
16264  {
16265  MoveTextOrGraphicButton->Enabled = true;
16266  }
16267  if(!Track->UserGraphicVector.empty())
16268  {
16269  MoveTextOrGraphicButton->Enabled = true;
16270  }
16271  SelectionValid = false;
16273  TimetableTitle = "";
16274  SetCaption(0);
16275  } break;
16276 
16277  case PrefDirMode:
16278  Screen->Cursor = TCursor(-11); //Hourglass in case many pref dirs
16282  PrefDirPanel->Visible = true;
16283  PrefDirPanelLabel->Caption = "Preferred direction selection";
16284 
16285  InfoPanel->Visible = true;
16286  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select preferred direction start location (right click to erase)";
16287  PrefDirKey->Visible = true;
16288  ModeMenu->Enabled = false;
16289  SigImagePanel->Visible = false; // new at v2.3.0
16290  FileMenu->Enabled = false;
16292  {
16293  ShowMessage("Preferred direction correctness can be difficult to check by eye\n"
16294  "alone, especially for large railways, so an automated conflict\n"
16295  "check is available in the 'Edit' menu when in preferred\n"
16296  "direction mode.\n\n"
16297  "This message will not be shown again.");
16299  }
16300 // set edit menu items
16302  AddPrefDirButton->Enabled = false;
16303  DeleteOnePrefDirButton->Enabled = false;
16305  if(EveryPrefDir->PrefDirSize() > 0)
16306  {
16307  DeleteAllPrefDirButton->Visible = true;
16308  DeleteAllPrefDirButton->Enabled = true;
16309  SaveImageAndPrefDirsMenuItem->Enabled = true;
16310  }
16311  else
16312  {
16313  DeleteAllPrefDirButton->Enabled = false;
16314  SaveImageAndPrefDirsMenuItem->Enabled = false;
16315  }
16316  ExitPrefDirButton->Enabled = true;
16317  ClearandRebuildRailway(33); // to mark PrefDirs & clear earlier PrefDir markers
16318 // TimetableTitle = ""; no need to unload timetable if only PrefDirs being changed
16319 // SetCaption();
16320  Screen->Cursor = TCursor(-2); //Arrow
16321  break;
16322 
16323  case OperMode: // if there are any PrefDirs, set to SigPref, else to NoSigNonPref; start in Paused mode
16327  OperatingPanel->Visible = true;
16328  OperatingPanelLabel->Caption = "Operation";
16329 
16330  CallingOnButton->Visible = false;
16331  PresetAutoSigRoutesButton->Visible = true;
16332  if(!EveryPrefDir->PrefDirVector.empty())//condition added at v2.10.0
16333  {
16334  PresetAutoSigRoutesButton->Enabled = true;
16335  }
16336  else
16337  {
16338  PresetAutoSigRoutesButton->Enabled = false;
16339  }
16340  InfoPanel->Visible = true;
16341  SigImagePanel->Visible = false; // new at v2.3.0
16342  ModeMenu->Enabled = false;
16343  FileMenu->Enabled = false;
16344  EditMenu->Enabled = false;
16345  ImageMenu->Enabled = true;
16346  SaveImageAndGridMenuItem->Enabled = true;
16347  SaveImageNoGridMenuItem->Enabled = true;
16348  if(EveryPrefDir->PrefDirSize() > 0)
16349  {
16350  SaveImageAndPrefDirsMenuItem->Enabled = true;
16351  }
16352  else
16353  {
16354  SaveImageAndPrefDirsMenuItem->Enabled = false;
16355  }
16356  SaveOperatingImageMenuItem->Enabled = true;
16357  AutoSigsFlag = false;
16358  MTBFEditBox->Visible = true; // visible at pre-start whether any value set or not, so can set a value if required
16360  {
16361  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
16362  }
16363  else
16364  {
16365  MTBFEditBox->Text = "";
16366  }
16367  MTBFEditBox->ReadOnly = false; // because this is prestart mode
16368  MTBFLabel->Visible = true;
16369  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
16371  if(EveryPrefDir->PrefDirSize() > 0)
16372  {
16373  ConsecSignalsRoute = true; // default starting conditions
16374  PreferredRoute = true; // default starting conditions
16375  }
16376  else // no PrefDirs
16377  {
16378  ConsecSignalsRoute = false;
16379  PreferredRoute = false;
16380  }
16381  OperateButton->Enabled = true;
16382  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
16383  ExitOperationButton->Enabled = true;
16384  TTClockAdjButton->Enabled = true;
16385  ShowPerformancePanel = false;
16386  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
16387  ShowOperatorActionPanel = false; // new at v2.2.0
16388  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
16389 
16391 
16392  Utilities->Clock2Stopped = false;
16396  TTClockSpeed = 1;
16397  TTClockSpeedLabel->Caption = "x1";
16400 
16401  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
16402  // format "16/06/2009 20:55:17"
16403  // avoid characters in filename:= / \ : * ? " < > |
16404  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " + TimetableTitle + ".txt";
16405 
16406  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
16407  if(Utilities->PerformanceFile.fail())
16408  {
16409  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
16410  " in the folder where the 'Railway.exe' program file resides");
16411  }
16412  Display->PerformanceLog(16, "Performance Log:"); //these statements separated at v2.13.0 as didn't separate in on-screen log
16413  Display->PerformanceLog(7777, "Railway: " + RailwayTitle);
16414  Display->PerformanceLog(7777, "Timetable: " + TimetableTitle);
16415  Display->PerformanceLog(7777, "Start Time: " + TrainController->TimetableStartTime.FormatString("hh:nn"));
16416  if(Utilities->DelayMode == Nil) //this section added at v2.13.0 for random delays
16417  {
16418  Display->PerformanceLog(7777, "No random delays selected");
16419  }
16420  else if(Utilities->DelayMode == Minor)
16421  {
16422  Display->PerformanceLog(7777, "Minor random delays selected");
16423  }
16424  else if(Utilities->DelayMode == Moderate)
16425  {
16426  Display->PerformanceLog(7777, "Moderate random delays selected");
16427  }
16428  else if(Utilities->DelayMode == Major)
16429  {
16430  Display->PerformanceLog(7777, "Major random delays selected");
16431  }
16433 // DisableRouteButtons(2); enable route setting or pre-start
16434 // DisablePanelsStoreMainMenuStates();
16435  TrainController->ContinuationAutoSigVector.clear(); // for restarting after earlier run
16436  AllRoutes->LockedRouteVector.clear(); // for restarting after earlier run
16437 // TrainController->Operate(1);//plot trains that are present at TT start time, ready for running - no, allow route plotting prior to train entries
16438 
16439 // reset all performance indicators
16448  TrainController->OnTimeExits = 0; //these 3 exits added at v2.9.2 - missed in error earlier
16469 
16470  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
16471  OAListBox->Clear();
16472  OAListBox->Items->Add(L""); // hints for OpActionPanel
16473  OAListBox->Items->Add(L"");
16474  OAListBox->Items->Add(L"");
16475  OAListBox->Items->Add(L"Left click");
16476  OAListBox->Items->Add(L"headcode to");
16477  OAListBox->Items->Add(L"locate train");
16478  OAListBox->Items->Add(L"");
16479  OAListBox->Items->Add(L"");
16480  OAListBox->Items->Add(L"Right click");
16481  OAListBox->Items->Add(L"headcode for");
16482  OAListBox->Items->Add(L"information");
16483  OAListBox->Items->Add(L"");
16484  OAListBox->Items->Add(L"");
16485  OAListBox->Items->Add(L"Left click and");
16486  OAListBox->Items->Add(L"hold grey area");
16487  OAListBox->Items->Add(L"to move panel");
16488  DelayMenu->Visible = true; //the following added at v2.13.0
16489  DelayMenu->Enabled = true;
16490  ClearandRebuildRailway(55); // so points display with one fillet
16491  break;
16492 
16493  case RestartSessionOperMode: // restart in Paused mode after a session load, sets both Level1Mode & Level2OperMode
16494  Level1Mode = OperMode;
16495 // Level2OperMode = Paused; this is now loaded during LoadInterface & could be PreStart of Paused
16498  OperatingPanel->Visible = true;
16499  OperatingPanelLabel->Caption = "Operation";
16500  DelayMenu->Visible = true; //added at v2.13.0
16501  DelayMenu->Enabled = true;
16502 
16503  CallingOnButton->Visible = true;
16504  PresetAutoSigRoutesButton->Visible = false;
16505  InfoPanel->Visible = true;
16506  ModeMenu->Enabled = false;
16507  SigImagePanel->Visible = false; // new at v2.3.0
16508  FileMenu->Enabled = false;
16509  EditMenu->Enabled = false;
16510  ImageMenu->Enabled = true;
16511  SaveImageAndGridMenuItem->Enabled = true;
16512  SaveImageNoGridMenuItem->Enabled = true;
16513  if(EveryPrefDir->PrefDirSize() > 0)
16514  {
16515  SaveImageAndPrefDirsMenuItem->Enabled = true;
16516  }
16517  else
16518  {
16519  SaveImageAndPrefDirsMenuItem->Enabled = false;
16520  }
16521  SaveOperatingImageMenuItem->Enabled = true;
16522 
16523  OperateButton->Enabled = true;
16524  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
16525  ExitOperationButton->Enabled = true;
16526  TTClockAdjButton->Enabled = true;
16529  if(Level2OperMode == Paused)
16530  {
16531  DisableRouteButtons(3); // could be PreStart or Paused
16532  }
16537  TTClockSpeed = 1;
16538  TTClockSpeedLabel->Caption = "x1";
16540  ShowPerformancePanel = false; // added at v2.2.0
16541  ShowOperatorActionPanel = false; // new at v2.2.0
16542  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
16543  OAListBox->Clear();
16544  OAListBox->Items->Add(L""); // hints for OpActionPanel
16545  OAListBox->Items->Add(L"");
16546  OAListBox->Items->Add(L"");
16547  OAListBox->Items->Add(L"Left click");
16548  OAListBox->Items->Add(L"headcode to");
16549  OAListBox->Items->Add(L"locate train");
16550  OAListBox->Items->Add(L"");
16551  OAListBox->Items->Add(L"");
16552  OAListBox->Items->Add(L"Right click");
16553  OAListBox->Items->Add(L"headcode for");
16554  OAListBox->Items->Add(L"information");
16555  OAListBox->Items->Add(L"");
16556  OAListBox->Items->Add(L"");
16557  OAListBox->Items->Add(L"Left click and");
16558  OAListBox->Items->Add(L"hold grey area");
16559  OAListBox->Items->Add(L"to move panel");
16560  if((TrainController->AvHoursIntValue > 0) || (Level2OperMode == PreStart)) // only visible if already set or if still in prestart mode
16561  {
16562  MTBFEditBox->Visible = true;
16564  {
16565  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
16566  }
16567  else
16568  {
16569  MTBFEditBox->Text = "";
16570  }
16571  MTBFEditBox->ReadOnly = false; // because this is still prestart mode
16572  MTBFLabel->Visible = true;
16573  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
16575  }
16576  else
16577  {
16578  MTBFEditBox->Visible = false;
16579  MTBFEditBox->Text = "";
16580  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
16581  MTBFLabel->Visible = false;
16582  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
16584  }
16585  if(Utilities->DelayMode == Nil) //this section added at v2.13.0 to indicate current state of random delays at start of session
16586  {
16587  Display->PerformanceLog(7777, "No random delays selected");
16588  }
16589  else if(Utilities->DelayMode == Minor)
16590  {
16591  Display->PerformanceLog(7777, "Minor random delays selected");
16592  }
16593  else if(Utilities->DelayMode == Moderate)
16594  {
16595  Display->PerformanceLog(7777, "Moderate random delays selected");
16596  }
16597  else if(Utilities->DelayMode == Major)
16598  {
16599  Display->PerformanceLog(7777, "Major random delays selected");
16600  }
16601  break;
16602 
16603  default:
16604  // No further recursion in BaseMode so OK
16605  Level1Mode = BaseMode;
16606  SetLevel1Mode(29);
16607  break;
16608  }
16609  api_main_mode_ = int(Level1Mode); //added at v2.10.0
16610  session_api_->dump(); // update session INI file
16611  Utilities->CallLogPop(103);
16612 }
16613 
16614 // ---------------------------------------------------------------------------
16615 
16617 {
16618  try
16619  {
16620  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2TrackMode");
16621  if(Level1Mode != TrackMode)
16622  {
16623  // No further recursion in BaseMode so OK
16624  Level1Mode = BaseMode;
16625  SetLevel1Mode(20);
16626  Utilities->CallLogPop(1115);
16627  return;
16628  }
16630  {
16631  Utilities->CallLogPop(104);
16632  return;
16633  }
16634  switch(Level2TrackMode) // use the data member
16635  {
16636  case AddTrack:
16638  InfoPanel->Visible = true;
16639  InfoPanel->Caption = "ADDING TRACK: Select element then left click to add it. Right click an element to remove it.";
16640  LengthConversionPanel->Visible = false; // in case had been in distance setting mode
16641  SpeedConversionPanel->Visible = false; // in case had been in distance setting mode
16642  TrackElementPanel->Visible = true;
16643  TrackElementPanel->Enabled = true;
16644  SigAspectButton->Visible = true;
16645  SigAspectButton->Enabled = true;
16646  ClearandRebuildRailway(34); // to replot grid if required & clear any other unwanted items
16648  SetLengthsButton->Enabled = false;
16649  // section added at v2.8.0 so buttons show correctly after a paste
16650  SetGapsButton->Enabled = false;
16651  TrackOKButton->Enabled = false;
16652  if(Track->GapsUnset(9))
16653  {
16654  SetGapsButton->Enabled = true;
16655  }
16656  // only enable if there are gaps still to be set (returns false for no track)
16657  else
16658  {
16659  if(!(Track->NoActiveTrack(3)) && !(Track->IsTrackFinished()))
16660  {
16661  TrackOKButton->Enabled = true;
16662  }
16663  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
16664  }
16665  // end of 2.8.0 addition
16666  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
16667  {
16668  SetLengthsButton->Enabled = true;
16669  }
16670  UserGraphicReselectPanel->Visible = false;
16671  SelectLengthsFlag = false; // in case still set though probably won't be
16672  EditMenu->Enabled = true; // added at v2.6.0 to allow edits for an empty screen so track elements can fill a selected area
16673  SetTrackModeEditMenu(6); //added at v2.10.0 to set menu items
16674  break;
16675 
16676  case AddGraphic:
16677  InfoPanel->Visible = true;
16678  InfoPanel->Caption = "ADDING GRAPHIC: Left click layout to add SELECTED graphic, right click to remove ANY graphic.";
16679  break;
16680 
16681  case SelectGraphic:
16682  InfoPanel->Visible = true;
16683  InfoPanel->Caption = "SELECTING USER GRAPHIC: Select the graphic file then add as many as necessary to the layout.";
16684  break;
16685 
16686  case GapSetting:
16687  int HLoc, VLoc, Count;
16688  Count = Track->NumberOfGaps(0);
16689  if(div(Count, 2).rem == 1) // condition OK
16690  {
16691  ShowMessage("Can't connect, there are an odd number of gaps");
16693  SetLevel1Mode(77);
16695  // No further recursion in AddTrack so OK
16696  SetLevel2TrackMode(40);
16697  Utilities->CallLogPop(105);
16698  return;
16699  }
16700  if(!HighLightOneGap(2, HLoc, VLoc)) // condition OK
16701  // need to call this here to start gap setting process off,
16702  // called in MainScreenMouseDown hereafter. Function returns false for either a LocError (links not yet
16703  // complete) or no more gaps to be highlighted
16704  {
16705  // shouldn't reach here as later gaps covered in MainScreenMouseDown but leave & give error message
16706  ShowMessage("Error - Even number of gaps but all set after first call to HighLightOneGap");
16708  SetLevel1Mode(78);
16710  // No further recursion in AddTrack so OK
16711  SetLevel2TrackMode(41);
16712  Utilities->CallLogPop(106);
16713  return; // all gaps set
16714  }
16715  InfoPanel->Visible = true;
16716  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting gap";
16717  UserGraphicReselectPanel->Visible = false;
16719  break;
16720 
16721  case AddText:
16722  InfoPanel->Visible = true;
16723  InfoPanel->Caption = "ADDING/EDITING TEXT: Left click to add, right click first letter to erase, or left click first letter to edit)";
16724  if(TextHandler->TextVectorSize(13) > 0)
16725  {
16726  MoveTextOrGraphicButton->Enabled = true;
16727  }
16728  else
16729  {
16730  MoveTextOrGraphicButton->Enabled = false;
16731  }
16732  UserGraphicReselectPanel->Visible = false;
16733  ClearandRebuildRailway(58); // to drop DistanceKey if was displayed
16734  break;
16735 
16736  case MoveTextOrGraphic:
16737  InfoPanel->Visible = true;
16738  InfoPanel->Caption = "MOVING TEXT OR GRAPHIC: If text left click first letter, if graphic left click anywhere, then drag";
16739  UserGraphicReselectPanel->Visible = false;
16740  ClearandRebuildRailway(59); // to drop DistanceKey if was displayed
16741  break;
16742 
16743  case AddLocationName:
16744  InfoPanel->Visible = true;
16745  InfoPanel->Caption = "NAMING LOCATIONS: Click on location element to add or change name";
16746  ClearandRebuildRailway(35); // to get rid of earlier red rectangle
16747  UserGraphicReselectPanel->Visible = false;
16748  SetTrackBuildImages(12);
16749  break;
16750 
16751  case DistanceStart:
16752  InfoPanel->Visible = true;
16753  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select first location (only non-default elements marked)";
16754  DistanceKey->Visible = true;
16755  LengthConversionPanel->Visible = true;
16756  SpeedConversionPanel->Visible = true;
16757  UserGraphicReselectPanel->Visible = false;
16758  ClearandRebuildRailway(36); // to get rid of earlier unwanted markings
16759  break;
16760 
16761  case DistanceContinuing:
16762  InfoPanel->Visible = true;
16763  if(ConstructPrefDir->PrefDirSize() == 1)
16764  {
16765  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select next location";
16766  }
16767  else
16768  {
16769  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
16770  }
16771  UserGraphicReselectPanel->Visible = false;
16772  ClearandRebuildRailway(54); // to remove earlier end marker if present
16773  break;
16774 
16775  case TrackSelecting:
16776  Track->CopyFlag = false;
16777  if(!SelectionValid)
16778  {
16779  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay
16780  }
16781  // the old SelectRect (only called when entered from SelectMenuItemClick, & not from
16782  // ReselectMenuItemClick)
16783  InfoPanel->Visible = true;
16784  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
16785  SelectMenuItem->Enabled = false;
16786  ReselectMenuItem->Enabled = false;
16787  CancelSelectionMenuItem->Enabled = true;
16788  UserGraphicReselectPanel->Visible = false;
16789  break;
16790 
16791  case CopyMoving:
16792  Track->CopyFlag = true;
16793  InfoPanel->Visible = true;
16794  InfoPanel->Caption = "COPYING: Left click in selection && drag";
16795  CutMenuItem->Enabled = false;
16796  CopyMenuItem->Enabled = false;
16797  FlipMenuItem->Enabled = false;
16798  MirrorMenuItem->Enabled = false;
16799  RotRightMenuItem->Enabled = false;
16800  RotLeftMenuItem->Enabled = false;
16801  RotateMenuItem->Enabled = false;
16802  PasteMenuItem->Enabled = true;
16803  // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 - don't allow the option if copying (dropped at 2.4.0 as all pastes are with attributes)
16804  DeleteMenuItem->Enabled = false;
16805  SelectLengthsMenuItem->Enabled = false;
16806  SelectBiDirPrefDirsMenuItem->Visible = false;
16807  CheckPrefDirConflictsMenuItem->Visible = false;
16808  CancelSelectionMenuItem->Enabled = true;
16812  UserGraphicReselectPanel->Visible = false;
16813  break;
16814 
16815  case CutMoving:
16816  {
16817  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
16818  // erase track elements within selected region
16819  Track->CopyFlag = false;
16820  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
16821  int ErasedTrackVectorPosition;
16822  Screen->Cursor = TCursor(-11); // Hourglass;
16823  InfoPanel->Visible = true;
16824  InfoPanel->Caption = "CUT PROCESSING: Please do not click the mouse";
16825  InfoPanel->Update();
16826  for(int H = SelectRect.left; H < SelectRect.right; H++)
16827  {
16828  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
16829  {
16830  Track->EraseTrackElement(2, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
16831  if(EraseSuccessfulFlag)
16832  {
16833  if(ErasedTrackVectorPosition > -1) //may be an inactive element that was erased
16834  {
16835  EveryPrefDir->RealignAfterTrackErase(1, ErasedTrackVectorPosition);
16836  }
16837  NeedToLink = true;
16838  }
16839  }
16840  }
16841 
16842  // erase text elements within selected region
16843  int LowSelectHPos = SelectRect.left * 16;
16844  int HighSelectHPos = SelectRect.right * 16;
16845  int LowSelectVPos = SelectRect.top * 16;
16846  int HighSelectVPos = SelectRect.bottom * 16;
16847  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
16848  {
16849  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
16850  TextPtr--) // reverse to prevent skipping during erase
16851  {
16852  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
16853  HighSelectVPos))
16854  {
16855  if(TextHandler->TextErase(1, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
16856  {
16857  ;
16858  } // unused condition
16859 
16860  TextChangesMade = true;
16861  }
16862  }
16863  }
16864  // erase graphic elements that fall wholly within region to be overwritten
16865  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
16866  {
16867  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
16868  GraphicPtr--) // reverse to prevent skipping during erase
16869  {
16870  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
16871  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
16872  {
16873  Track->UserGraphicVector.erase(GraphicPtr);
16874  GraphicChangesMade = true;
16875  }
16876  }
16877  }
16878  Track->CheckMapAndTrack(11); // test
16879  Track->CheckMapAndInactiveTrack(10); // test
16880  Track->CheckLocationNameMultiMap(19); // test
16881  Screen->Cursor = TCursor(-2); // Arrow;
16882  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
16883  // if track not linked to begin with then becomes linked if NeedToLink false
16884  if(NeedToLink)
16885  {
16886  Track->SetTrackFinished(false); // corrected for v2.1.0
16887  }
16888  InfoPanel->Caption = "CUTTING: Left click in selection && drag";
16889  CutMenuItem->Enabled = false;
16890  CopyMenuItem->Enabled = false;
16891  FlipMenuItem->Enabled = false;
16892  MirrorMenuItem->Enabled = false;
16893  RotRightMenuItem->Enabled = false;
16894  RotLeftMenuItem->Enabled = false;
16895  RotateMenuItem->Enabled = false;
16896  PasteMenuItem->Enabled = true;
16897  // PasteWithAttributesMenuItem->Enabled = true; //new at v2.2.0 - option enabled if cutting (dropped at 2.4.0 as all pastes are with attributes)
16898  DeleteMenuItem->Enabled = false;
16899  SelectLengthsMenuItem->Enabled = false;
16900  SelectBiDirPrefDirsMenuItem->Visible = false;
16901  CheckPrefDirConflictsMenuItem->Visible = false;
16902  CancelSelectionMenuItem->Enabled = true;
16905  if(NeedToLink || TextChangesMade || GraphicChangesMade)
16906  {
16907  ResetChangedFileDataAndCaption(20, true); // true for NonPrefDirChangesMade
16908  }
16909  ClearandRebuildRailway(37); // to overplot the erased elements with SelectBitmap
16910  UserGraphicReselectPanel->Visible = false;
16912  } break;
16913 
16914  case Pasting:
16915  {
16916  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
16917  int HDiff = SelectBitmapHLoc - SelectRect.left; // SelectBitmapHLoc/VLoc is the paste position & SelectRect.left/top is the original position
16918  int VDiff = SelectBitmapVLoc - SelectRect.top;
16919  if(!SelectionValid && !CancelSelectionFlag) // may be pasting into a new application so use clipboard, new at v2.8.0
16920  {
16921  bool ValidResult;
16922  RecoverClipboard(0, ValidResult); // new at v2.8.0
16923  if(ValidResult)
16924  {
16925  HDiff = Display->DisplayOffsetH - SelectRect.left; // SelectRect.left & top recovered in clipboard
16926  VDiff = Display->DisplayOffsetV - SelectRect.top;
16927  SelectBitmapHLoc = Display->DisplayOffsetH; // so the area to erase corresponds to the paste area (TLHC of screen = DisplayOffsetH & V)
16929  SelectionValid = false; // don't want reselect in new app after paste
16930  Track->SetTrackFinished(false); // would be set to false in other app but not in this so set it to false here
16932  {
16933  UnicodeString MessageStr =
16934  "Please be aware of the relevant conditions when pasting " "a railway segment from a different application.\n"
16935  "These are set out in section 3.5 of the manual and " "on-screen help under the heading 'Pasting in an application "
16936  "after cutting or copying from a different application'.\n\n" "This warning will not be shown again.\n\n" "Proceed?";
16937  int button = Application->MessageBox(MessageStr.c_str(), L"Warning", MB_YESNO | MB_ICONWARNING);
16939  if(button == IDNO)
16940  {
16941  CancelSelectionMenuItem->Click(); // reset clipboard etc
16942  Utilities->CallLogPop(2271);
16943  return;
16944  }
16945  }
16946  }
16947  else
16948  {
16949  Application->MessageBoxW(L"Unable to paste (clipboard is invalid) - possibly because another application has changed it)", L"Warning", MB_OK | MB_ICONWARNING);
16950  CancelSelectionMenuItem->Click(); // reset clipboard etc
16951  TrainController->LogEvent("ValidResult false in case Pasting - probably due to error in RecoverClipboard - see earlier log");
16952  Utilities->CallLogPop(2272); //EClipboardException (here as search term only)
16953  return;
16954  }
16955  }
16956  if(CancelSelectionFlag) // plot cut area in original position in case moved
16957  {
16960  HDiff = 0;
16961  VDiff = 0;
16962  }
16963  Clipboard()->Clear(); // already cleared & closed if recovered clipboard but not otherwise so clear & close here
16964  Clipboard()->Close();
16967  bool NeedToLink = false;
16968  bool TrackLinkingRequiredFlag;
16969  Screen->Cursor = TCursor(-11); // Hourglass;
16970  InfoPanel->Visible = true;
16971  InfoPanel->Caption = "PASTING: Please wait";
16972  InfoPanel->Update();
16973  // erase track elements
16974  int LowSelectHLoc = SelectBitmapHLoc;
16975  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
16976  int LowSelectVLoc = SelectBitmapVLoc;
16977  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
16978  bool TrackEraseSuccessfulFlag; // needed but not used here
16979  int ErasedTrackVectorPosition;
16980  // new quick method of erasing, only need H & V values
16981  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
16982  {
16983  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
16984  {
16985  Track->EraseTrackElement(5, x, y, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, false);
16986  if(ErasedTrackVectorPosition > -1)
16987  {
16988  EveryPrefDir->RealignAfterTrackErase(2, ErasedTrackVectorPosition);
16989  }
16990  }
16991  }
16992 
16993  // erase text elements that fall within region to be overwritten
16994  int LowSelectHPos = SelectBitmapHLoc * 16;
16995  int HighSelectHPos = (SelectBitmapHLoc * 16) + SelectBitmap->Width;
16996  int LowSelectVPos = SelectBitmapVLoc * 16;
16997  int HighSelectVPos = (SelectBitmapVLoc * 16) + SelectBitmap->Height;
16998  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
16999  {
17000  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
17001  TextPtr--) // reverse to prevent skipping during erase
17002  {
17003  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
17004  HighSelectVPos))
17005  {
17006  if(TextHandler->TextErase(2, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
17007  {
17008  ;
17009  } // unused condition
17010 
17011  }
17012  }
17013  }
17014  // erase graphic elements that fall wholly within region to be overwritten
17015  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
17016  {
17017  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
17018  GraphicPtr--) // reverse to prevent skipping during erase
17019  {
17020  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
17021  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
17022  {
17023  Track->UserGraphicVector.erase(GraphicPtr);
17024  }
17025  }
17026  }
17027  // change the H & V values in SelectVector to the new positions in case Reselect chosen
17028  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
17029  {
17030  Track->SelectVectorAt(35, x).HLoc += HDiff;
17031  Track->SelectVectorAt(1, x).VLoc += VDiff;
17032  }
17033 
17034  // add the new track elements
17035  AnsiString LocName;
17036  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
17037  {
17038  if(Track->CopyFlag) // blank all names if copying, lengths & speedlimits stay
17039  {
17040  Track->SelectVectorAt(80, x).LocationName = "";
17042  }
17043  else //cut, check if element has a name and if so remove same existing name from name map and track vector
17044  {
17045  LocName = Track->SelectVectorAt(82, x).LocationName;
17046  if(LocName == "")
17047  {
17048  LocName = Track->SelectVectorAt(83, x).ActiveTrackElementName;
17049  }
17050  if(LocName != "")
17051  {
17052  Track->EraseLocationAndActiveTrackElementNames(6, LocName); //this will keep erasing adjacent element names but the last one will be pasted and not erased
17053  //and that will name all linked elements so should work ok
17054  int HPos = 0, VPos = 0;
17055  if(TextHandler->FindText(5, LocName, HPos, VPos))
17056  {
17057  ;
17058  }
17059  {
17060  if(EraseLocationNameText(4, LocName, HPos, VPos))
17061  {
17062  ;
17063  } // condition not used
17064  }
17065  }
17066  }
17067  bool InternalChecks = false;
17068  // if(Track->PastingWithAttributes) //new at v2.2.0 to select the new funtion & skip multimap checks //drop in v2.4.0
17069  // {
17071  TrackLinkingRequiredFlag, InternalChecks);
17072  // new at v2.2.0 & used in place of PlotAndAddTrackElement to keep length & speed values
17073  // }
17074  /* drop this in v2.4.0 as all pastes are with attributes
17075  else //'Aspect' parameter added to PlotAndAdd... at v2.2.0 so can plot signals correctly (always four-aspect before)
17076  {
17077  int Aspect;
17078  if(Track->SelectVectorAt(15, x).TrackType != SignalPost) Aspect = 0; //if an '0' value appears with a SignalPost then must be adding track
17079  //this combination allows the funtion to distinguish between adding track and plotting with attributes
17080  else if(Track->SelectVectorAt(16, x).SigAspect == TTrackElement::GroundSignal) Aspect = 1;
17081  else if(Track->SelectVectorAt(17, x).SigAspect == TTrackElement::TwoAspect) Aspect = 2;
17082  else if(Track->SelectVectorAt(18, x).SigAspect == TTrackElement::ThreeAspect) Aspect = 3;
17083  else Aspect = 4;
17084  Track->PlotAndAddTrackElement(2, Track->SelectVectorAt(19, x).SpeedTag, Aspect, Track->SelectVectorAt(20, x).HLoc, Track->SelectVectorAt(21, x).VLoc, TrackLinkingRequiredFlag, InternalChecks);
17085  }
17086  */
17087  if(TrackLinkingRequiredFlag)
17088  {
17089  NeedToLink = true;
17090  }
17091  }
17092 
17093  //add the pref dir elements, added at v2.9.0
17094  int ATVecPos;
17095  bool FoundFlag;
17096  if(SelectPrefDir->PrefDirSize() > 0) // skip iteration if empty
17097  {
17098  // keep contents valid in case reselect
17100  PDVIt++)
17101  {
17102  PDVIt->HLoc += HDiff; // for reselect
17103  PDVIt->VLoc += VDiff; // for reselect
17104  //need to reset TrackVectorPosition in case any elements erased before linking, as if so EveryPrefDir can only be erased too if it has the correct TrackVectorPosition
17105  ATVecPos = Track->GetVectorPositionFromTrackMap(60, PDVIt->HLoc, PDVIt->VLoc, FoundFlag);
17106  if(!FoundFlag)
17107  {
17108  throw Exception("Failed to find TrackVectorPosition in PrefDir setting for Paste");
17109  }
17110  PDVIt->SetTrackVectorPosition(ATVecPos);
17111 
17112  //reset all Conns & ConnLinkPos values so won't be erased during a later cut, they will be set in RebuildPrefDirVector which is called when track linked
17113  for(int x = 0; x < 4; x++)
17114  {
17115  PDVIt->Conn[x] = -1;
17116  PDVIt->ConnLinkPos[x] = -1;
17117  }
17119  }
17121  }
17122 
17123  // add the new text items
17124  if(!TextHandler->SelectTextVector.empty()) // skip iteration if empty else have an error
17125  {
17126  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->SelectTextVector.begin(); TextPtr < TextHandler->SelectTextVector.end(); TextPtr++)
17127  {
17128  TextPtr->HPos += HDiff * 16;
17129  TextPtr->VPos += VDiff * 16;
17130  AnsiString TempString = TextPtr->TextString;
17131  // have to create a new TextItem in order to create a new Font object
17132  /* drop in v2.4.0 as all pastes are paste with attributes
17133  if(!Track->PastingWithAttributes) //new at v2.2.0 to deal with the new location prefix '##**' //drop in v2.4.0
17134  {
17135  if(TextPtr->TextString.SubString(1,4) != "##**") //added for named locations so can delete in a simple paste but
17136  //use in PastingWithAttributes
17137  {
17138  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TextPtr->TextString, TextPtr->Font);
17139  TextHandler->TextVectorPush(0, TextItem); //if a normal paste include normal text but not location text
17140  }
17141  else TextPtr->TextString = ""; //delete the name for a simple paste
17142  }
17143  */
17144  // else //if pasting with attributes paste all text but strip the '##**' prefix if present
17145  // {
17146  if(TextPtr->TextString.SubString(1, 4) == "##**")
17147  {
17148  TempString = TextPtr->TextString.SubString(5, TextPtr->TextString.Length()); // don't change SelectTextVector value
17149  if(Track->CopyFlag)
17150  {
17151  TextPtr->TextString = ""; // change SelectTextVector value as reselect shouldn't have locations if copied
17152  TempString = "";
17153  }
17154  }
17155  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TempString, TextPtr->Font);
17157  // }
17158  }
17159  }
17160  // add new graphic items
17161  if(!Track->SelectGraphicVector.empty()) // skip iteration if empty else have an error
17162  {
17163  // keep contents of SelectVector valid in case reselect
17164  for(TTrack::TUserGraphicVector::iterator GraphicPtr = Track->SelectGraphicVector.begin(); GraphicPtr < Track->SelectGraphicVector.end();
17165  GraphicPtr++)
17166  {
17167  GraphicPtr->HPos += HDiff * 16; // for reselect
17168  GraphicPtr->VPos += VDiff * 16; // for reselect
17169  Track->UserGraphicVector.push_back(*GraphicPtr);
17170  }
17171  }
17172  Track->SkipLocationNameMultiMapCheck = false; // renamed in v2.4.0 - reset the flag after pasting complete, otherwise multimap checks always skipped
17173  Track->CopyFlag = false;
17174  Track->CheckMapAndTrack(7); // test
17175  Track->CheckMapAndInactiveTrack(7); // test
17176  Track->CheckLocationNameMultiMap(7); // test
17177  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
17178  // if track not linked to begin with then becomes linked if NeedToLink false
17179  if(NeedToLink)
17180  {
17181  Track->SetTrackFinished(false); // corrected for v2.1.0
17182  }
17183  Screen->Cursor = TCursor(-2); // Arrow;
17184  SetTrackBuildImages(14);
17186  // Level1Mode = TrackMode; //dropped as prevents AddTrack being called to display track elements
17187  // SetLevel1Mode(79);
17188  SetTrackModeEditMenu(5); // this is called from the above but is still needed to enable Select (& Reselect if pasted in same app) menu items
17189  PasteMenuItem->Enabled = false;
17190  UserGraphicReselectPanel->Visible = false;
17191  if(Level2TrackMode != AddTrack) // no need to set if already set in an earlier call
17192  {
17194  // No further recursion in AddTrack so OK
17195  SetLevel2TrackMode(42);
17196  }
17197  } break;
17198 
17199  case Deleting:
17200  {
17201  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
17202  Track->CopyFlag = false;
17203  UnicodeString MessageStr = "Selected area will be deleted - proceed?";
17204  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
17205  if(button == IDNO)
17206  {
17207  break;
17208  }
17209  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
17210  int ErasedTrackVectorPosition;
17211  Screen->Cursor = TCursor(-11); // Hourglass;
17212  InfoPanel->Visible = true;
17213  InfoPanel->Caption = "DELETING: Please wait";
17214  InfoPanel->Update();
17215  for(int H = SelectRect.left; H < SelectRect.right; H++)
17216  {
17217  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
17218  {
17219  Track->EraseTrackElement(3, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
17220  if(EraseSuccessfulFlag)
17221  {
17222  if(ErasedTrackVectorPosition > -1)
17223  {
17224  EveryPrefDir->RealignAfterTrackErase(3, ErasedTrackVectorPosition);
17225  }
17226  NeedToLink = true;
17227  }
17228  }
17229  }
17230  // erase text elements that fall within selected region
17231  int LowSelectHPos = SelectRect.left * 16;
17232  int HighSelectHPos = SelectRect.right * 16;
17233  int LowSelectVPos = SelectRect.top * 16;
17234  int HighSelectVPos = SelectRect.bottom * 16;
17235  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
17236  {
17237  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
17238  TextPtr--) // reverse to prevent skipping during erase
17239  {
17240  AnsiString Check = TextPtr->TextString;
17241  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
17242  HighSelectVPos))
17243  {
17244  if(TextHandler->TextErase(3, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
17245  {
17246  ;
17247  } // unused condition
17248 
17249  TextChangesMade = true;
17250  }
17251  }
17252  }
17253  // erase graphic elements that fall within selected region
17254  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
17255  {
17256 
17257  // Isglassen05 (vilhelmgg@gmail.com) reported an error via email and attached an error file on 31/07/20. The error was in the following line which was:
17258 
17259  // for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->SelectGraphicVector.end() - 1); GraphicPtr >= Track->SelectGraphicVector.begin();
17260  // GraphicPtr--) // reverse to prevent skipping during erase
17261 
17262  // i.e if the railway included one or more user graphics but the SelectGraphicVector didn't include any, then GraphicPtr wouldn't point to anything and the program would fail
17263  // corrected 01/08/20 by using UserGraphicVector (as it should have been) for SelectGraphicVector. New version v2.4.3.
17264 
17265  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
17266  GraphicPtr--) // reverse to prevent skipping during erase
17267  {
17268  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
17269  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
17270  {
17271  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = (Track->UserGraphicVector.end() - 1);
17272  UserGraphicPtr >= Track->UserGraphicVector.begin(); UserGraphicPtr--) // reverse to prevent skipping during erase
17273  {
17274  if((UserGraphicPtr->HPos == GraphicPtr->HPos) && (UserGraphicPtr->VPos == GraphicPtr->VPos) &&
17275  (UserGraphicPtr->Width == GraphicPtr->Width) && (UserGraphicPtr->Height == GraphicPtr->Height) &&
17276  (UserGraphicPtr->FileName == GraphicPtr->FileName))
17277  {
17278  Track->UserGraphicVector.erase(UserGraphicPtr);
17279  GraphicChangesMade = true;
17280  }
17281  }
17282  }
17283  }
17284  }
17285  // clear the selectvectors
17287  TextHandler->SelectTextVector.clear();
17288  Track->SelectGraphicVector.clear();
17290  Track->CheckMapAndTrack(10); // test
17291  Track->CheckMapAndInactiveTrack(9); // test
17292  Track->CheckLocationNameMultiMap(15); // test
17293  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
17294  // if track not linked to begin with then becomes linked if NeedToLink false
17295  if(NeedToLink)
17296  {
17297  Track->SetTrackFinished(false); // corrected for v2.1.0
17298  }
17299  if(NeedToLink || TextChangesMade || GraphicChangesMade)
17300  {
17301  ResetChangedFileDataAndCaption(21, true); // true for NonPrefDirChangesMade
17302  }
17303  Screen->Cursor = TCursor(-2); // Arrow;
17306  SetLevel1Mode(80);
17308  // No further recursion in AddTrack so OK
17309  UserGraphicReselectPanel->Visible = false;
17310  SetLevel2TrackMode(43);
17311  } break;
17312 
17313  default:
17314  // No further recursion in TrackMode so OK
17315  Track->CopyFlag = false;
17317  SetLevel1Mode(21);
17318  UserGraphicReselectPanel->Visible = false;
17319  break;
17320  }
17321  Utilities->CallLogPop(107);
17322  }
17323  catch (const EClipboardException &e) //non-error catch
17324  {
17325  TrainController->LogEvent("Clipboard error in SetLevel2TrackMode");
17326  Utilities->CallLogPop(2404);
17327  }
17328 }
17329 
17330 // ---------------------------------------------------------------------------
17331 
17333 {
17334  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2PrefDirMode");
17335  if(Level1Mode != PrefDirMode)
17336  {
17337  // No further recursion in BaseMode so OK
17338  Level1Mode = BaseMode;
17339  SetLevel1Mode(22);
17340  Utilities->CallLogPop(108);
17341  return;
17342  }
17344  {
17345  Utilities->CallLogPop(109);
17346  return;
17347  }
17348  switch(Level2PrefDirMode) // use the data member
17349  {
17350  case PrefDirContinuing:
17351  {
17352  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
17353  InfoPanel->Visible = true;
17354  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
17355  {
17356  AddPrefDirButton->Enabled = true; // this and the line below are to remove focus from any other button that might have it, prior to
17357  AddPrefDirButton->SetFocus(); // disabling the AddPrefDir button, so pressing enter does nothing, it is reset to the AddPrefDir
17358  }
17359  AddPrefDirButton->Enabled = false; // button later if it becomes enabled
17360  DeleteOnePrefDirButton->Enabled = false;
17361  bool LeadingPointsAtLastElement = false;
17362  if(!ConstructPrefDir->EndPossible(0, LeadingPointsAtLastElement))
17363  {
17364  if(LeadingPointsAtLastElement) // size must be > 1
17365  {
17366  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Can't end on leading points, select next location or truncate";
17367  DeleteOnePrefDirButton->Enabled = true;
17368  }
17369  else // size == 1, DeleteOnePrefDirButton->Enabled remains false
17370  {
17371  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select next preferred direction location (right click to truncate)";
17372  }
17373  }
17374  else // size > 1 & EndPossible
17375  {
17376  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Add selection or select next location (right click to truncate)";
17377  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
17378  {
17379  AddPrefDirButton->Enabled = true;
17380  AddPrefDirButton->SetFocus(); // so can just press 'Enter' key
17381  }
17382  DeleteOnePrefDirButton->Enabled = true;
17383  }
17384  ExitPrefDirButton->Enabled = true;
17385  ClearandRebuildRailway(40); // to show truncated PrefDirs
17386  } break;
17387 
17388  case PrefDirSelecting:
17389  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay the old SelectRect
17390  InfoPanel->Visible = true;
17391  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
17392  SelectMenuItem->Enabled = false;
17393  ReselectMenuItem->Enabled = false;
17394  CancelSelectionMenuItem->Enabled = true;
17395  break;
17396 
17397  default:
17398  // No further recursion in PrefDirMode so OK
17400  SetLevel1Mode(23);
17401  break;
17402  }
17403  Utilities->CallLogPop(110);
17404 }
17405 
17406 // ---------------------------------------------------------------------------
17407 
17409 {
17410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2OperMode");
17411  if(Level1Mode != OperMode)
17412  {
17413  // No further recursion in BaseMode so OK
17414  Level1Mode = BaseMode;
17415  SetLevel1Mode(24);
17416  Utilities->CallLogPop(111);
17417  return;
17418  }
17419  if(Level2OperMode == NoOperMode)
17420  {
17421  Utilities->CallLogPop(112);
17422  return;
17423  }
17424  DelayMenu->Visible = true; //these added at v2.13.0
17425  DelayMenu->Enabled = true;
17426  CallingOnButton->Visible = true;
17427  PresetAutoSigRoutesButton->Visible = false;
17428  switch(Level2OperMode) // use the data member
17429  {
17430  case Operating:
17431  {
17432  // have to use braces as otherwise the default case bypasses the initialisation of local variables
17433  OperateButton->Enabled = true;
17434  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
17435  ExitOperationButton->Enabled = true;
17436  TTClockAdjButton->Enabled = false;
17437  if(TTClockSpeed == 2)
17438  {
17439  TTClockSpeedLabel->Caption = "x2";
17440  }
17441  else if(TTClockSpeed == 4)
17442  {
17443  TTClockSpeedLabel->Caption = "x4";
17444  }
17445  else if(TTClockSpeed == 8)
17446  {
17447  TTClockSpeedLabel->Caption = "x8";
17448  }
17449  else if(TTClockSpeed == 16)
17450  {
17451  TTClockSpeedLabel->Caption = "x16";
17452  }
17453  else if(TTClockSpeed == 0.5)
17454  {
17455  TTClockSpeedLabel->Caption = "x1/2";
17456  }
17457  else if(TTClockSpeed == 0.25)
17458  {
17459  TTClockSpeedLabel->Caption = "x1/4";
17460  }
17461  else if(TTClockSpeed == 0.125)
17462  {
17463  TTClockSpeedLabel->Caption = "x1/8";
17464  }
17465  else if(TTClockSpeed == 0.0625)
17466  {
17467  TTClockSpeedLabel->Caption = "x1/16";
17468  }
17469  else
17470  {
17471  TTClockSpeed = 1;
17472  TTClockSpeedLabel->Caption = "x1";
17473  }
17474  AnsiString TimeMessage = Utilities->Format96HHMMSS(TDateTime(PauseEntryRestartTime)) + ": ";
17476  {
17477  // send message to performance log
17478  if(TTClockSpeed == 2)
17479  {
17480  Display->PerformanceLog(6, TimeMessage + "Timetable clock speed changed to twice normal");
17481  }
17482  else if(TTClockSpeed == 4)
17483  {
17484  Display->PerformanceLog(7, TimeMessage + "Timetable clock speed changed to four times normal");
17485  }
17486  else if(TTClockSpeed == 8)
17487  {
17488  Display->PerformanceLog(8, TimeMessage + "Timetable clock speed changed to eight times normal");
17489  }
17490  else if(TTClockSpeed == 16)
17491  {
17492  Display->PerformanceLog(9, TimeMessage + "Timetable clock speed changed to sixteen times normal");
17493  }
17494  else if(TTClockSpeed == 0.5)
17495  {
17496  Display->PerformanceLog(10, TimeMessage + "Timetable clock speed changed to half normal");
17497  }
17498  else if(TTClockSpeed == 0.25)
17499  {
17500  Display->PerformanceLog(11, TimeMessage + "Timetable clock speed changed to quarter normal");
17501  }
17502  else if(TTClockSpeed == 0.125)
17503  {
17504  Display->PerformanceLog(14, TimeMessage + "Timetable clock speed changed to one eighth normal");
17505  }
17506  else if(TTClockSpeed == 0.0625)
17507  {
17508  Display->PerformanceLog(15, TimeMessage + "Timetable clock speed changed to one sixteenth normal");
17509  }
17510  else
17511  {
17512  Display->PerformanceLog(12, TimeMessage + "Timetable clock speed changed to normal");
17513  }
17514  }
17515  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
17516  if(TTClockTimeChange > 0.000347) // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
17517  {
17518  // send message to performance log
17519  int MinsIncrease = ((TTClockTimeChange * 1440) + 0.5); // add 30 secs to ensure truncates correctly
17520  int HoursIncrease = 0;
17521  while(MinsIncrease >= 60)
17522  {
17523  HoursIncrease++;
17524  MinsIncrease -= 60;
17525  }
17526  if(HoursIncrease == 0)
17527  {
17528  TimeMessage += "Timetable clock incremented by " + AnsiString(MinsIncrease) + "m";
17529  }
17530  else if(MinsIncrease == 0)
17531  {
17532  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h";
17533  }
17534  else
17535  {
17536  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h " + AnsiString(MinsIncrease) + "m";
17537  }
17538  Display->PerformanceLog(13, TimeMessage);
17539  }
17540  WarningHover = false;
17543  {
17544  MTBFEditBox->Visible = true;
17545  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
17546  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
17547  MTBFLabel->Visible = true;
17548  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
17550  }
17551  else
17552  {
17553  MTBFEditBox->Visible = false;
17554  MTBFEditBox->Text = "";
17555  MTBFLabel->Visible = false;
17556  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
17558  }
17559  TrainController->BaseTime = TDateTime::CurrentDateTime();
17560 // StopTTClockFlag already false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
17561  } break;
17562 
17563  case Paused:
17564  OperateButton->Enabled = true;
17565  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
17566  ExitOperationButton->Enabled = true;
17567  TTClockAdjButton->Enabled = true;
17572 // StopTTClockFlag stays false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
17575  break;
17576 
17577  // don't need a separate case for PreStart
17578 
17579  default:
17580  // No further recursion in OperMode so OK
17581  Level1Mode = OperMode;
17582  SetLevel1Mode(25);
17583  break;
17584  }
17585  api_oper_mode_ = int(Level2OperMode); //added at v2.10.0
17586  session_api_->dump(); // update session INI file
17587  Utilities->CallLogPop(113);
17588 }
17589 
17590 // ---------------------------------------------------------------------------
17591 
17592 void TInterface::ApproachLocking(int Caller, TDateTime TTClockTime)
17593 {
17594  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ApproachLocking");
17595  float LockDelay = 120.0;
17596 
17597  if(!AllRoutes->LockedRouteVector.empty())
17598  {
17599  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
17600  {
17601  bool BreakFlag = false;
17602  if(AllRoutes->TrackIsInARoute(5, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
17603  {
17604  TOneRoute &Route = AllRoutes->GetModifiableRouteAt(0, LRVIT->RouteNumber);
17605  if((TTClockTime - LRVIT->LockStartTime) > TDateTime(LockDelay / 86400))
17606  {
17607  TrainController->LogEvent("LockedRouteRemoved," + AnsiString(LRVIT->TruncateTrackVectorPosition) + "," +
17608  AnsiString(LRVIT->LastTrackVectorPosition));
17609  while(Route.LastElementPtr(9)->GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
17610  {
17611  // examine the element one earlier in the route than the last
17612  if(!(AllRoutes->TrackIsInARoute(6, Route.LastElementPtr(10)->Conn[Route.LastElementPtr(11)->GetELinkPos()],
17613  Route.LastElementPtr(12)->ConnLinkPos[Route.LastElementPtr(13)->GetELinkPos()])))
17614  {
17615  BreakFlag = true;
17616  }
17617  AllRoutes->RemoveRouteElement(1, Route.LastElementPtr(14)->HLoc, Route.LastElementPtr(15)->VLoc, Route.LastElementPtr(16)->GetELink());
17618  if(BreakFlag)
17619  {
17620  break; // train removed earlier element from route so stop here
17621  }
17622  }
17623  if(!BreakFlag)
17624  {
17625  // still need to remove the element at the TruncateTrackVectorPosition
17626  if(Route.LastElementPtr(17)->GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
17627  {
17628  AllRoutes->RemoveRouteElement(2, Route.LastElementPtr(18)->HLoc, Route.LastElementPtr(19)->VLoc,
17629  Route.LastElementPtr(20)->GetELink());
17630  }
17631  }
17632  AllRoutes->CheckMapAndRoutes(10); // test
17633  AllRoutes->LockedRouteVector.erase(LRVIT);
17634  if(!Display->ZoomOutFlag)
17635  {
17636  ClearandRebuildRailway(17); // to get rid of route graphics
17637  }
17639  }
17640  }
17641  else
17642  {
17643  AllRoutes->LockedRouteVector.erase(LRVIT);
17644  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
17645  // hence no longer needed so get rid of it
17646  }
17647  }
17648  }
17649  Utilities->CallLogPop(743);
17650 }
17651 
17652 // ---------------------------------------------------------------------------
17653 
17654 void TInterface::ContinuationAutoSignals(int Caller, TDateTime TTClockTime)
17655 {
17656  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ContinuationAutoSignals");
17658  {
17660  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
17661  AutoSigVectorIT--)
17662  {
17663  // Below added at v2.1.0 to prevent locked autosig continuation routes from clearing signals
17664  // need to identify the Continuation element in the route & check if it's in a locked route. If it is then don't call
17665  // SetTrailingSignalsOnContinuationRoute as all signals must stay red.
17666  TPrefDirElement TempPrefDirElement;
17667  int TempLockedVectorNumber;
17668  int LastRouteElement = AllRoutes->GetFixedRouteAt(220, AutoSigVectorIT->RouteNumber).PrefDirSize() - 1;
17669  int TVNum = AllRoutes->GetFixedRouteAt(221, AutoSigVectorIT->RouteNumber).GetFixedPrefDirElementAt(246, LastRouteElement).GetTrackVectorPosition();
17670  // this will be a continuation (error thrown in SetTrailingSignalsOnContinuationRoute if not) & XLinkPos is always 0 for
17671  // route exiting at a continuation
17672  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(14, TVNum, 0, TempPrefDirElement, TempLockedVectorNumber))
17673  {
17674  continue;
17675  }
17676  // end of additions
17677  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->FirstDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 0))
17678  {
17679  AllRoutes->SetTrailingSignalsOnContinuationRoute(1, AutoSigVectorIT->RouteNumber, 0);
17680  AutoSigVectorIT->AccessNumber++;
17681  continue;
17682  }
17683  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->SecondDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 1))
17684  {
17685  AllRoutes->SetTrailingSignalsOnContinuationRoute(2, AutoSigVectorIT->RouteNumber, 1);
17686  AutoSigVectorIT->AccessNumber++;
17687  continue;
17688  }
17689  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->ThirdDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 2))
17690  {
17691  AllRoutes->SetTrailingSignalsOnContinuationRoute(3, AutoSigVectorIT->RouteNumber, 2);
17692  AutoSigVectorIT->AccessNumber++;
17693  continue;
17694  }
17695  }
17696  // examine all vector for any expired values & erase
17697  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
17698  AutoSigVectorIT--)
17699  {
17700  if(AutoSigVectorIT->AccessNumber > 2)
17701  {
17702  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT); // erase expired entries - reverse interation so OK to erase
17703  }
17704  }
17705  }
17706  Utilities->CallLogPop(744);
17707 }
17708 
17709 // ---------------------------------------------------------------------------
17710 
17712 {
17713  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackTrainFloat");
17714  TPoint MousePoint = Mouse->CursorPos;
17715  int ScreenX = MousePoint.x - MainScreen->ClientOrigin.x;
17716  int ScreenY = MousePoint.y - MainScreen->ClientOrigin.y;
17717 
17718  if(SkipTTActionsListBox->Visible || (!OAListBoxRightMouseButtonDown && ((ScreenX > (MainScreen->Width - 1)) || (ScreenY > (MainScreen->Height - 1)) || (ScreenX < 0) || (ScreenY < 0))))
17719  {
17720  // added !OAListBoxRightMouseButtonDown at v2.7.0 so can still obtain info & move to trains from OAListBox even if they are out of the main screen area
17721  // added SkipTTActionsListBox->Visible at v2.11.0 so floating window when thuis is displayed
17722  FloatingPanel->Visible = false;
17723  Utilities->CallLogPop(1432);
17724  return;
17725  }
17726  if(PerformancePanel->Visible)
17727  {
17728  if((MousePoint.x >= PerformancePanel->Left) && (MousePoint.x <= (PerformancePanel->Left + PerformancePanel->Width)) &&
17729  ((MousePoint.y - ClientOrigin.y) >= PerformancePanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
17730  (PerformancePanel->Top + PerformancePanel->Height)))
17731  {
17732  // dont show floating window if mouse over performance panel
17733  FloatingPanel->Visible = false;
17734  Utilities->CallLogPop(1715);
17735  return;
17736  }
17737  }
17738  if(TimetableEditPanel->Visible) // added at v2.5.1 as showed track info behind panel
17739  {
17740  if((MousePoint.x >= TimetableEditPanel->Left) && (MousePoint.x <= (TimetableEditPanel->Left + TimetableEditPanel->Width)) &&
17741  ((MousePoint.y - ClientOrigin.y) >= TimetableEditPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
17742  (TimetableEditPanel->Top + TimetableEditPanel->Height)))
17743  {
17744  // dont show floating window if mouse over TimetableEditPanel
17745  FloatingPanel->Visible = false;
17746  Utilities->CallLogPop(2240);
17747  return;
17748  }
17749  }
17750  AnsiString TrackFloat = "", TrainStatusFloat = "", TrainTTFloat = "";
17751  bool ShowTrackFloatFlag = false, ShowTrainStatusFloatFlag = false, ShowTrainTTFloatFlag = false;
17752  int HLoc, VLoc;
17753 
17754  Track->GetTrackLocsFromScreenPos(4, HLoc, VLoc, ScreenX, ScreenY);
17755 
17756  if(Display->ZoomOutFlag)
17757  {
17758  Utilities->CallLogPop(1123);
17759  return;
17760  }
17761  bool MouseOverOAPanel = false;
17762 // this flag added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
17763  if(OperatorActionPanel->Visible)
17764  {
17765  if((MousePoint.x >= OperatorActionPanel->Left) && (MousePoint.x <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
17766  ((MousePoint.y - ClientOrigin.y) >= OperatorActionPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
17767  (OperatorActionPanel->Top + OperatorActionPanel->Height)))
17768  {
17769  MouseOverOAPanel = true;
17770  }
17771  }
17772  if((TrackInfoOnOffMenuItem->Caption == "Hide") && !MouseOverOAPanel)
17773  // MouseOverOAPanel condit added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
17774  {
17775  bool ActiveTrackFoundFlag = false, InactiveTrackFoundFlag = false, TwoTrack = false;
17776  AnsiString Length01Str = "", Length23Str = "", SpeedLimit01Str = "", SpeedLimit23Str = "";
17777  AnsiString StationEntryStopLinkPos1Str = "", StationEntryStopLinkPos2Str = "";
17778  AnsiString ATrackSN = "", ATrackTN = "", IATrackSN = "", LengthAndSpeedCaption = "";
17779  AnsiString SigAspectString = ""; // new at version 0.6
17780  int ActiveVecPos = Track->GetVectorPositionFromTrackMap(5, HLoc, VLoc, ActiveTrackFoundFlag);
17781  TTrack::TIMPair InactiveVecPositions = Track->GetVectorPositionsFromInactiveTrackMap(3, HLoc, VLoc, InactiveTrackFoundFlag);
17782  TTrackElement ActiveTrackElement, InactiveTrackElement;
17783  if(InactiveTrackFoundFlag)
17784  {
17785  InactiveTrackElement = Track->InactiveTrackElementAt(32, InactiveVecPositions.first); // only need one for the name
17786  IATrackSN = InactiveTrackElement.LocationName;
17787  }
17788  if(ActiveTrackFoundFlag)
17789  {
17790  ActiveTrackElement = Track->TrackElementAt(449, ActiveVecPos);
17791  ATrackSN = ActiveTrackElement.LocationName;
17792  StationEntryStopLinkPos1Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos1);
17793  StationEntryStopLinkPos2Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos2);
17794  ATrackTN = ActiveTrackElement.ActiveTrackElementName;
17795  if((ATrackTN != "") && (!InactiveTrackFoundFlag || ((InactiveTrackElement.TrackType != Platform) &&
17796  (InactiveTrackElement.TrackType != NamedNonStationLocation)) ||
17797  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName)))
17798  {
17799  ShowMessage("Error - Track has timetable name without corresponding plat/named loc");
17800  }
17801  if(InactiveTrackFoundFlag && ((InactiveTrackElement.TrackType == Platform) || (InactiveTrackElement.TrackType == NamedNonStationLocation)) &&
17802  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName))
17803  {
17804  ShowMessage("Error - plat/named loc and track have different names, or plat/named loc named but not track");
17805  }
17806  if((ActiveTrackElement.TrackType == Points) || (ActiveTrackElement.TrackType == Bridge) || (ActiveTrackElement.TrackType == Crossover))
17807  {
17808  TwoTrack = true;
17809  }
17810  Length01Str = AnsiString(ActiveTrackElement.Length01);
17811  if(Length01Str == "-1")
17812  {
17813  Length01Str = "Not Set";
17814  }
17815  SpeedLimit01Str = AnsiString(ActiveTrackElement.SpeedLimit01);
17816  if(SpeedLimit01Str == "-1")
17817  {
17818  SpeedLimit01Str = "Not Set";
17819  }
17820  if(TwoTrack)
17821  {
17822  Length23Str = AnsiString(ActiveTrackElement.Length23);
17823  if(Length23Str == "-1")
17824  {
17825  Length23Str = "Not Set"; // shouldn't be -1 but leave in
17826  }
17827  SpeedLimit23Str = AnsiString(ActiveTrackElement.SpeedLimit23);
17828  if(SpeedLimit23Str == "-1")
17829  {
17830  SpeedLimit23Str = "Not Set"; // shouldn't be -1 but leave in
17831  }
17832  if((ActiveTrackElement.TrackType == Points) && (ActiveTrackElement.SpeedTag < 132))
17833  {
17834  LengthAndSpeedCaption = "Straight track length = " + Length01Str + " m" + '\n' + "Diverging track length = " + Length23Str + " m" + '\n' +
17835  "Straight track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Diverging track speed limit = " + SpeedLimit23Str + " km/h";
17836  }
17837  else if(ActiveTrackElement.TrackType == Points)
17838  {
17839  LengthAndSpeedCaption = "Left diverging track length = " + Length01Str + " m" + '\n' + "Right diverging track length = " + Length23Str +
17840  " m" + '\n' + "Left diverging track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Right diverging track Speed Limit = " +
17841  SpeedLimit23Str + " km/h";
17842  }
17843  else if(ActiveTrackElement.TrackType == Crossover)
17844  // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
17845  {
17846  if((ActiveTrackElement.SpeedTag == 15) || (ActiveTrackElement.SpeedTag == 46))
17847  {
17848  LengthAndSpeedCaption = "Horizontal track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
17849  "Horizontal track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
17850  }
17851  else if(ActiveTrackElement.SpeedTag == 47)
17852  {
17853  LengthAndSpeedCaption = "Horizontal track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
17854  "Horizontal track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
17855  }
17856  else if(ActiveTrackElement.SpeedTag == 45)
17857  {
17858  LengthAndSpeedCaption = "Vertical track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
17859  "Vertical track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
17860  }
17861  else if(ActiveTrackElement.SpeedTag == 44)
17862  {
17863  LengthAndSpeedCaption = "Vertical track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
17864  "Vertical track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
17865  }
17866  else if(ActiveTrackElement.SpeedTag == 16)
17867  {
17868  LengthAndSpeedCaption = "Top left to bottom right track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str +
17869  " m" + '\n' + "Top left to bottom right track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " +
17870  SpeedLimit23Str + " km/h";
17871  }
17872  }
17873  else // bridge
17874  {
17875  LengthAndSpeedCaption = "Top track length = " + Length01Str + " m" + '\n' + "Bottom track length = " + Length23Str + " m" + '\n' +
17876  "Top track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Bottom track speed limit = " + SpeedLimit23Str + " km/h";
17877  }
17878  }
17879  else
17880  {
17881  LengthAndSpeedCaption = "Track length = " + Length01Str + " m" + '\n' + "Track speed limit = " + SpeedLimit01Str + " km/h";
17882  }
17883  }
17884  if(ActiveTrackFoundFlag)
17885  {
17886  // note that now the "In timetable..." line removed much of the below could be simplified, but leave as is
17887  // in case wish to resurrect this line for any reason
17888  ShowTrackFloatFlag = true;
17889  if(ATrackTN != "") // has a timetable name & therefore has a valid platform or non-station name
17890  {
17891  TrackFloat = "Location = " + ATrackTN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
17892  }
17893  else if(ATrackSN != "") // no timetable name but location name, i.e. a footcrossing
17894  {
17895  TrackFloat = "Location = " + ATrackSN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
17896  }
17897 
17898  else if(InactiveTrackFoundFlag) // no timetable name yet but unnamed inactive element at same location (can't be a parapet if active element there)
17899  {
17900  TrackFloat = "Location unnamed\n" + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
17901  }
17902 
17903  else // no timetable or location name, just track
17904  {
17905  TrackFloat = LengthAndSpeedCaption + '\n' + "Track Element ID = " + AnsiString(ActiveTrackElement.ElementID);
17906  }
17907  if(ActiveTrackElement.TrackType == SignalPost) // new for version 0.6
17908  {
17909  if(ActiveTrackElement.SigAspect == TTrackElement::ThreeAspect)
17910  {
17911  SigAspectString = "\nThree-aspect signal";
17912  }
17913  else if(ActiveTrackElement.SigAspect == TTrackElement::TwoAspect)
17914  {
17915  SigAspectString = "\nTwo-aspect signal";
17916  }
17917  else if(ActiveTrackElement.SigAspect == TTrackElement::GroundSignal)
17918  {
17919  SigAspectString = "\nGround signal";
17920  }
17921  else
17922  {
17923  SigAspectString = "\nFour-aspect signal";
17924  }
17925  TrackFloat += SigAspectString;
17926  }
17927  } // if(ActiveFoundFlag)
17928  else if(InactiveTrackFoundFlag) // inactive element but no active element,
17929  // i.e. concourse or non-station name at a blank element
17930  {
17931  ShowTrackFloatFlag = true;
17932  if(InactiveTrackElement.TrackType != Parapet)
17933  {
17934  if(IATrackSN == "")
17935  {
17936  TrackFloat = "Location unnamed\nID = " + AnsiString(InactiveTrackElement.ElementID);
17937  }
17938  else
17939  {
17940  TrackFloat = "Location = " + IATrackSN + '\n' + "ID = " + AnsiString(InactiveTrackElement.ElementID);
17941  }
17942  }
17943  else // it is a parapet, just show the ID
17944  {
17945  TrackFloat = "ID = " + AnsiString(InactiveTrackElement.ElementID);
17946  }
17947  }
17948  }
17949 // end of TrackFloat section
17950 
17951  bool OAListBoxFloatRequired = false; // identifies which window needs the float
17952  if(Level1Mode == OperMode && ((TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") || (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")))
17953  // if caption is 'Hide' label is required
17954  {
17955  bool FoundFlag;
17956  AnsiString FormatOneDPStr = "####0.0";
17957  AnsiString FormatNoDPStr = "#######0";
17958  AnsiString MaxBrakeStr = ""; // , EntrySpeedStr="", HalfStr="", FullStr="", MaxAtHalfStr="";//test
17959  AnsiString SpecialStr = "";
17960  if(OperatorActionPanel->Visible) // added at v2.6.2 to show floating window for trains in actions due list
17961  {
17962  if(OAListBox->MouseInClient && !OperatorActionPanel->MouseInClient && OAListBoxRightMouseButtonDown)
17963  {
17964  int X = OAListBox->ScreenToClient(MousePoint).x;
17965  int Y = OAListBox->ScreenToClient(MousePoint).y;
17966  int TrainID = -1, ContinuationPos = -1;
17967  if(GetTrainIDOrContinuationPosition(1, X, Y, TrainID, ContinuationPos))
17968  {
17969  OAListBoxFloatRequired = true;
17970  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
17971  {
17972  ShowTrainStatusFloatFlag = true;
17973  }
17974  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
17975  {
17976  ShowTrainTTFloatFlag = true;
17977  }
17978  if((TrainID > -1) && (ShowTrainStatusFloatFlag || ShowTrainTTFloatFlag))
17979  {
17980  TTrain Train = TrainController->TrainVectorAtIdent(53, TrainID);
17981  TrainStatusFloat = GetTrainStatusFloat(0, TrainID, FormatNoDPStr, SpecialStr);
17982  TrainTTFloat = Train.FloatingTimetableString(1, Train.ActionVectorEntryPtr);
17983  }
17984  else if(ContinuationPos > -1)
17985  {
17986  GetTrainFloatingInfoFromContinuation(0, ContinuationPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
17987  }
17988  }
17989  }
17990  }
17991  if(!OAListBoxFloatRequired) // condition added at v2.6.2 so only one floating window can show
17992  {
17993  int VecPos = Track->GetVectorPositionFromTrackMap(6, HLoc, VLoc, FoundFlag);
17994  if(FoundFlag && !MouseOverOAPanel) // MouseOverOAPanel added at v2.7.0 to prevent trains showimng behind OA panel
17995  {
17996  if(Track->TrackElementAt(450, VecPos).TrainIDOnElement > -1)
17997  // if a bridge & 2 trains at that position will select the train with TrainIDOnElement set
17998  {
17999  int TrainID = Track->TrackElementAt(452, VecPos).TrainIDOnElement;
18000  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
18001  {
18002  ShowTrainStatusFloatFlag = true;
18003  TrainStatusFloat = GetTrainStatusFloat(1, TrainID, FormatNoDPStr, SpecialStr);
18004  }
18005  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
18006  {
18007  ShowTrainTTFloatFlag = true;
18008  TTrain Train = TrainController->TrainVectorAtIdent(54, TrainID);
18009  TrainTTFloat = Train.FloatingTimetableString(0, Train.ActionVectorEntryPtr);
18010  }
18011  }
18012 
18013  else if(Track->TrackElementAt(666, VecPos).TrackType == Continuation)
18014  // always give train information if a train present, but if not & either of train status or timetable info
18015  // selected then give next expected train to enter, or 'No trains expected'
18016  {
18017  TrainStatusFloat = "No trains expected";
18018  TrainTTFloat = "No timetable";
18019  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
18020  {
18021  ShowTrainStatusFloatFlag = true;
18022  }
18023  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
18024  {
18025  ShowTrainTTFloatFlag = true;
18026  }
18028  {
18029  GetTrainFloatingInfoFromContinuation(1, VecPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
18030  }
18031  }
18032  }
18033  }
18034  }
18035 // end of TrainFloat section
18036  AnsiString Caption;
18037 
18038  if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
18039  {
18040  FloatingPanel->Visible = false;
18041  Utilities->CallLogPop(1485);
18042  return; // return with label invisible
18043  }
18044  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
18045  {
18046  Caption = TrackFloat;
18047  }
18048  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
18049  {
18050  Caption = TrainStatusFloat;
18051  }
18052  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
18053  {
18054  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
18055  }
18056  else if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
18057  {
18058  if(TrainStatusFloat == "No trains expected")
18059  {
18060  Caption = TrainStatusFloat;
18061  }
18062  else
18063  {
18064  Caption = TrainTTFloat;
18065  }
18066  }
18067  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
18068  {
18069  if(TrainStatusFloat == "No trains expected")
18070  {
18071  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
18072  }
18073  else
18074  {
18075  Caption = TrainTTFloat + '\n' + '\n' + TrackFloat;
18076  }
18077  }
18078  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
18079  {
18080  if(TrainStatusFloat == "No trains expected")
18081  {
18082  Caption = TrainStatusFloat;
18083  }
18084  else
18085  {
18086  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat;
18087  }
18088  }
18089  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
18090  {
18091  if(TrainStatusFloat == "No trains expected")
18092  {
18093  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
18094  }
18095  else
18096  {
18097  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat + '\n' + '\n' + TrackFloat;
18098  }
18099  }
18100  int WindowOffsetLeft = 16;
18101  int WindowOffsetRight = 16;
18102  if(OAListBoxFloatRequired)
18103  {
18104  WindowOffsetLeft = 32;
18105  WindowOffsetRight = 64;
18106  }
18107  FloatingLabel->Caption = Caption; // set this here so dimensions correct in calculations, moved from below at v2.7.0
18108  FloatingPanel->Visible = true; // need this or dimensions still not valid, moved from below at v2.7.0
18109 
18110  int Left = ScreenX + MainScreen->Left + WindowOffsetRight; // so lhs of window is WindowOffset to the right of the mouse pos
18111 // this offset is because window position is relative to the interface form, whereas ScreenX & Y are relative to the MainScreen, which is
18112 // offset 32 to the right and 95 down from the interface form
18113  if((Left + FloatingPanel->Width) > MainScreen->Left + MainScreen->Width)
18114  {
18115  Left = ScreenX - FloatingPanel->Width + 32 - WindowOffsetLeft;
18116  }
18117 // so rhs of window is 32 - WindowOffset to the left of the mouse pos (+32 would be at mouse pos)
18118  int Top = ScreenY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
18119 
18120  if((Top + FloatingPanel->Height) > MainScreen->Top + MainScreen->Height)
18121  {
18122  Top = ScreenY - FloatingPanel->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
18123  // but, top may now be off the top of the screen, if so position at the top of the screen, as always need to see the top, if have to
18124  // lose something then it's best to be from the bottom
18125  if(Top < 30) // use 30 instead of MainScreen->Top [95] as top can go off MainScreen providing it doesn't reach the information panel, as that would
18126  // obscure the window
18127  {
18128  Top = 30;
18129  }
18130  }
18131 /* if((Left != FloatingPanel->Left) || (Top != FloatingPanel->Top)) //dropped at v2.7.0 as causes more flickler than allowing window to move with mouse
18132  {
18133  FloatingPanel->Visible = false; // so doesn't flicker when reposition
18134  FloatingPanel->Left = Left;
18135  FloatingPanel->Top = Top;
18136  Utilities->CallLogPop(1917);
18137  return;
18138  }
18139 */
18140 
18141  FloatingPanel->Left = Left; // new at v2.7.0 in place of above
18142  FloatingPanel->Top = Top;
18143 
18144 // FloatingLabel->Caption = Caption; moved up at v2.7.0
18145 // FloatingPanel->Visible = true; // moved up at v2.7.0
18146  FloatingPanel->BringToFront();
18147  Utilities->CallLogPop(746);
18148 }
18149 
18150 // ---------------------------------------------------------------------------
18151 
18152 void TInterface::GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat,
18153  AnsiString &TrainTTFloat)
18154 {
18155  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainFloatingInfoFromContinuation");
18157  int LineSpeedLimit = Track->TrackElementAt(906, VecPos).SpeedLimit01; // speed only in 01 as a continuation
18158  float EntrySpeed;
18160  {
18161  while((CTEIt != TrainController->ContinuationTrainExpectationMultiMap.end()) && ((CTEIt->second.VectorPosition != VecPos) ||
18162  (CTEIt->second.TrainDataEntryPtr->TrainOperatingDataVector.at(CTEIt->second.RepeatNumber).RunningEntry != NotStarted)))
18163  {
18164  CTEIt++;
18165  }
18167  {
18168  TTrainDataEntry *TTDEPtr = CTEIt->second.TrainDataEntryPtr;
18169  AnsiString ServiceReferenceInfo = "";
18170  // Repeat information
18171  if(TTDEPtr->NumberOfTrains > 1) // Service reference information
18172  {
18173  if(CTEIt->second.RepeatNumber == 0)
18174  {
18175  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
18176  {
18177  ServiceReferenceInfo = "\nFirst service of ref. " + TTDEPtr->ServiceReference;
18178  }
18179  else
18180  {
18181  ServiceReferenceInfo = "\nFirst service";
18182  }
18183  }
18184  else if(CTEIt->second.HeadCode == TTDEPtr->ServiceReference)
18185  {
18186  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber);
18187  }
18188  else
18189  {
18190  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber) + " of ref. " + TTDEPtr->ServiceReference;
18191  }
18192  }
18193  else
18194  {
18195  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
18196  {
18197  ServiceReferenceInfo = "\nService reference " + TTDEPtr->ServiceReference;
18198  }
18199  }
18200  if(TTDEPtr->ActionVector.at(0).SignallerControl) // entry at 0 is the start entry
18201  {
18202  SpecialStr = "\nTrain under signaller control";
18203  EntrySpeed = TTDEPtr->SignallerSpeed;
18204  if(EntrySpeed > LineSpeedLimit)
18205  {
18206  EntrySpeed = LineSpeedLimit;
18207  }
18208  }
18209  else
18210  {
18211  EntrySpeed = TTDEPtr->StartSpeed;
18212  if(EntrySpeed > LineSpeedLimit)
18213  {
18214  EntrySpeed = LineSpeedLimit;
18215  }
18216  }
18217  if((CTEIt->first + TDateTime(1.0 / 1440)) < TrainController->TTClockTime) // has to be at least 1 min late to show as late
18218  {
18219  TDateTime TempTime = CTEIt->first;
18220 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
18221  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
18222  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nDelayed, was due at " + Utilities->Format96HHMM(TempTime);
18223  }
18224  else
18225  {
18226  TDateTime TempTime = CTEIt->first;
18227 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
18228  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
18229  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nExpected at " + Utilities->Format96HHMM(TempTime);
18230  }
18231  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
18232  {
18233  if(!TTDEPtr->ActionVector.at(0).SignallerControl) // if signaller control there's no timetable & SpecialStr covers this
18234  {
18235  TrainTTFloat = TrainController->ContinuationEntryFloatingTTString(0, TTDEPtr, CTEIt->second.RepeatNumber, CTEIt->second.IncrementalMinutes,
18236  CTEIt->second.IncrementalDigits);
18237  }
18238  }
18239  }
18240  }
18241  Utilities->CallLogPop(2262);
18242 }
18243 
18244 // ---------------------------------------------------------------------------
18245 
18246 AnsiString TInterface::GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
18247 // new at v2.6.2 to make it easier to show also from actions due panel
18248 {
18249  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainStatusFloat");
18250  AnsiString HeadCode = "", ServiceReferenceInfo = "", Status = "", CurrSpeedStr = "", BrakePCStr = "", NextStopStr = "", TimeLeftStr = "",
18251  TimeToNextMovementStr = "", MassStr = "", PowerStr = "";
18252  AnsiString FormatOneDPStr = "####0.0", MaxBrakeStr = "", MaxSpeedStr = "", TrainStatusFloat;
18253 
18254  double CurrSpeed;
18255  TTrain Train = TrainController->TrainVectorAtIdent(1, TrainID);
18256  MassStr = AnsiString::FormatFloat(FormatNoDPStr, ((double)Train.Mass) / 1000); // Te
18257  PowerStr = AnsiString::FormatFloat(FormatNoDPStr, Train.PowerAtRail / 1000 / 0.8); // kW
18258  if(Train.BeingCalledOn)
18259  {
18260  MaxSpeedStr = "30";
18261  }
18262  else
18263  {
18264  MaxSpeedStr = AnsiString::FormatFloat(FormatNoDPStr, Train.MaxRunningSpeed);
18265  }
18266  TDateTime ElapsedDeltaT = TrainController->TTClockTime - Train.EntryTime;
18267  TDateTime FirstHalfTimeDeltaT = Train.ExitTimeHalf - Train.EntryTime;
18268  TDateTime SecondHalfTimeDeltaT = Train.ExitTimeFull - Train.EntryTime - FirstHalfTimeDeltaT;
18269  TDateTime TimeLeft;
18270  double BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
18271  MaxBrakeStr = AnsiString::FormatFloat(FormatNoDPStr, (Train.MaxBrakeRate * Train.Mass / 9810));
18272  HeadCode = Train.HeadCode;
18273  if(Train.TrainDataEntryPtr->NumberOfTrains > 1) // Service reference information added at v0.6b
18274  {
18275  if(Train.RepeatNumber == 0)
18276  {
18277  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
18278  {
18279  ServiceReferenceInfo = "\nFirst service of ref. " + Train.TrainDataEntryPtr->ServiceReference;
18280  }
18281  else
18282  {
18283  ServiceReferenceInfo = "\nFirst service";
18284  }
18285  }
18286  else if(HeadCode == Train.TrainDataEntryPtr->ServiceReference)
18287  {
18288  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber);
18289  }
18290  else
18291  {
18292  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber) + " of ref. " + Train.TrainDataEntryPtr->ServiceReference;
18293  }
18294  }
18295  else
18296  {
18297  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
18298  {
18299  ServiceReferenceInfo = "\nService reference " + Train.TrainDataEntryPtr->ServiceReference;
18300  }
18301  }
18302  if(Train.Stopped())
18303  {
18304  if(Train.SignallerStopped)
18305  {
18306  Status = "Stopped on signaller's instruction"; // if stopped for any other reason that will diplay
18307  }
18308  if(Train.NotInService)
18309  {
18310  Status = "Not in service"; // not used so far but leave it in
18311  }
18312  if(Train.StoppedAtBuffers)
18313  {
18314  Status = "Stopped at buffers";
18315  }
18316  if(Train.StoppedAtSignal)
18317  {
18318  Status = "Stopped at signal";
18319  }
18320  if(Train.StoppedForTrainInFront)
18321  {
18322  Status = "Stopped - forward track occupied"; // before station stop as want to display station stop if that set
18323  }
18324  if(Train.RevisedStoppedAtLoc())
18325  {
18326  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName;
18327  }
18328  if((Train.RevisedStoppedAtLoc()) && (Train.StoppedForTrainInFront))
18329  {
18330  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName + " + forward track occupied";
18331  }
18332  if(Train.StoppedWithoutPower)
18333  {
18334  if(Train.TrainFailed)
18335  {
18336  Status = "Stopped without power - train failed";
18337  }
18338  else
18339  {
18340  Status = "Stopped without power";
18341  }
18342  }
18343  if(Train.StoppedAfterSPAD)
18344  {
18345  Status = "Stopped - signal passed at danger";
18346  }
18347  if(Train.Derailed)
18348  {
18349  Status = "Derailed";
18350  }
18351  if(Train.Crashed)
18352  {
18353  Status = "Crashed";
18354  }
18355  CurrSpeed = 0;
18356  }
18357  else if(Train.OneLengthAccelDecel)
18358  {
18359  if(Train.FirstHalfMove)
18360  {
18361  Status = "Accelerating"; // just display a linear speed rise over half length
18362  BrakePCRate = 0; // reset to proper value during braking
18363  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
18364  }
18365  else
18366  {
18367  BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
18368  if(BrakePCRate < 55)
18369  {
18370  Status = "Light braking";
18371  }
18372  else if(BrakePCRate < 90)
18373  {
18374  Status = "Heavy braking";
18375  }
18376  else
18377  {
18378  Status = "Emergency braking";
18379  }
18380  CurrSpeed = Train.ExitSpeedHalf - 3.6 * (Train.BrakeRate * (TrainController->TTClockTime - Train.ExitTimeHalf) * 86400.0);
18381  }
18382  }
18383  else if(Train.BrakeRate > 0.01)
18384  {
18385  if(BrakePCRate < 55)
18386  {
18387  Status = "Light braking";
18388  }
18389  else if(BrakePCRate < 90)
18390  {
18391  Status = "Heavy braking";
18392  }
18393  else
18394  {
18395  Status = "Emergency braking";
18396  }
18397  CurrSpeed = Train.EntrySpeed - 3.6 * (Train.BrakeRate * ElapsedDeltaT * 86400.0);
18398  }
18399 
18400  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedHalf > (Train.EntrySpeed + 0.01)) && Train.FirstHalfMove)
18401  {
18402  Status = "Accelerating"; // just display a linear speed rise over half length
18403  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
18404  }
18405 
18406  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull > (Train.ExitSpeedHalf + 0.01)) && !Train.FirstHalfMove)
18407  {
18408  Status = "Accelerating";
18409  CurrSpeed = Train.ExitSpeedHalf +
18410  ((Train.ExitSpeedFull - Train.ExitSpeedHalf) * (double(ElapsedDeltaT - FirstHalfTimeDeltaT) / double(SecondHalfTimeDeltaT)));
18411  }
18412 
18413  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull <= Train.ExitSpeedHalf) && !Train.FirstHalfMove)
18414  {
18415  if(Train.PowerAtRail < 1)
18416  {
18417  if(Train.TrainFailed)
18418  {
18419  Status = "Coasting - train failed";
18420  }
18421  else
18422  {
18423  Status = "Coasting - no power";
18424  }
18425  CurrSpeed = Train.ExitSpeedFull;
18426  }
18427  else
18428  {
18429  Status = "Constant speed";
18430  CurrSpeed = Train.ExitSpeedFull;
18431  }
18432  }
18433 
18434  else // No braking, first half move, ExitSpeedHalf <= EntrySpeed
18435  {
18436  if(Train.PowerAtRail < 1) // as designed there is no way a vehicle can coast without having failed
18437  {
18438  if(Train.TrainFailed)
18439  {
18440  Status = "Coasting - train failed";
18441  }
18442  else
18443  {
18444  Status = "Coasting - no power";
18445  }
18446  CurrSpeed = Train.ExitSpeedHalf;
18447  }
18448  else
18449  {
18450  Status = "Constant speed";
18451  CurrSpeed = Train.ExitSpeedHalf;
18452  }
18453  }
18454  if(Train.TimetableFinished)
18455  {
18456  if(Train.TrainMode == Signaller)
18457  {
18458  NextStopStr = "At signaller's discretion";
18459  }
18460  else
18461  {
18462  NextStopStr = "None";
18463  }
18464  }
18465  else
18466  {
18467  NextStopStr = Train.FloatingLabelNextString(0, Train.ActionVectorEntryPtr);
18468  }
18469  if(Train.TrainMode == Signaller)
18470  {
18471  SpecialStr = "Train under signaller control" + AnsiString('\n');
18472  }
18473  else if(Train.BeingCalledOn && !Train.RevisedStoppedAtLoc())
18474  {
18475  SpecialStr = "Restricted speed - being called on" + AnsiString('\n');
18476  }
18477  double RemTimeHalf = 86400.0 * double(Train.ExitTimeHalf - TrainController->TTClockTime);
18478  if(RemTimeHalf < 0)
18479  {
18480  RemTimeHalf = 0;
18481  }
18482  double RemTimeFull = 86400.0 * double(Train.ExitTimeFull - TrainController->TTClockTime);
18483  if(RemTimeFull < 0)
18484  {
18485  RemTimeFull = 0;
18486  }
18487  if(RemTimeHalf > 0)
18488  {
18489  TimeLeft = RemTimeHalf;
18490  }
18491  else
18492  {
18493  TimeLeft = RemTimeFull;
18494  }
18495  TimeToNextMovementStr = "Time to next movement (sec) = " + TimeLeftStr.FormatFloat(FormatOneDPStr, TimeLeft);
18496  if(Train.Stopped())
18497  {
18498  TimeToNextMovementStr = "";
18499  }
18500  if(Train.StoppedAtLocation && (Train.ActionVectorEntryPtr->DepartureTime > TDateTime(-1))) //if departure not next action then ignore NewDelay
18501  { //added at v2.13.0
18502  if(int(Train.NewDelay) == 1)
18503  {
18504  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
18505  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + '\n' +
18506  "Additional delay here of 1 minute\nNext: " +
18507  NextStopStr;
18508  }
18509  else if(int(Train.NewDelay) > 1)
18510  {
18511  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
18512  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + '\n' +
18513  "Additional delay here of " + AnsiString(int(Train.NewDelay)) + " minutes\nNext: " +
18514  NextStopStr;
18515  }
18516  else
18517  {
18518  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
18519  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + '\n' + "Next: " +
18520  NextStopStr;
18521  }
18522  }
18523  else if(Train.Stopped()) //stopped anywhere else or not a departure next
18524  {
18525  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
18526  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + '\n' + "Next timetabled action: " +
18527  NextStopStr; //changed to 'Next timetabled action:' at v2.13.0 instead of 'Next:' to make clear it doesn't include delays
18528  }
18529  else
18530  {
18531  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
18532  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + ": " +
18533  CurrSpeedStr.FormatFloat(FormatNoDPStr, CurrSpeed) + "km/h" + '\n' + "Next timetabled action: " + NextStopStr;
18534  } //changed to 'Next timetabled action:' at v2.13.0 instead of 'Next:' to make clear it doesn't include delays
18535  Utilities->CallLogPop(2263);
18536  return(TrainStatusFloat);
18537 }
18538 
18539 // ---------------------------------------------------------------------------
18540 
18541 void TInterface::FlashingGraphics(int Caller, TDateTime Now)
18542 // following section checks to see if GapFlashFlag set & flashes the Gap graphics if so
18543 // Gap flashing is cancelled on any mousedown event
18544 
18545 {
18546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FlashingGraphics");
18547 // deal with flashing GapFlash graphics (only in basic mode so no need to check for trains)
18549  {
18550  if(WarningFlash)
18551  {
18552  Track->GapFlashGreen->PlotOverlay(4, Display); // only plotted if PlotOverlay reset
18554  }
18555  else
18556  {
18557  Track->GapFlashGreen->PlotOriginal(17, Display); // only plotted if PlotOverlay set
18559  }
18560  }
18562  {
18563  if(WarningFlash)
18564  {
18569  Display->Update();
18570  }
18571  else
18572  {
18577  Display->Update();
18578  }
18579  }
18580 // deal with gap setting - added at v2.6.1 to make location easier
18582  {
18584  }
18586  {
18587  Display->Ellipse(2, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB0G0R5);
18588  }
18590  {
18592  }
18594  {
18595  Display->Ellipse(3, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB5G5R5);
18596  }
18597 // deal with other flashing graphics
18599  {
18600  if((Now - RouteFlashStartTime) < TDateTime(RouteFlashDuration / 86400))
18601  {
18602  // cancel if train is moving & arrives on any part of flashing route
18604  {
18605  Track->RouteFlashFlag = false;
18607  ClearandRebuildRailway(18); // because using ConstructRoute->RouteFlash.PlotOriginal() can plot wrong point fillet as well as
18608  // original (if proposed route would change point). With this can dispense with ConstructRoute->RouteFlash.PlotOriginal()
18609  Utilities->CallLogPop(75);
18610  return;
18611  }
18612  InfoPanel->Visible = true;
18613  if(Level2OperMode == PreStart)
18614  {
18615  InfoPanel->Caption = "PRE-START: Route setting in progress";
18616  }
18617  else
18618  {
18619  InfoPanel->Caption = "OPERATING: Route setting in progress";
18620  }
18621  if(WarningFlash)
18622  {
18624  }
18625  else
18626  {
18628  }
18629  }
18630  else
18631  {
18632 // ConstructRoute->RouteFlash.PlotOriginal(); don't need with clearand....
18633 // stop clock while converting route as can take several seconds
18634  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
18636  if(PreferredRouteFlag)
18637  {
18639  }
18640  else
18641  {
18643  }
18644  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
18645  TrainController->BaseTime = TDateTime::CurrentDateTime();
18647  Track->RouteFlashFlag = false;
18649  ClearandRebuildRailway(19); // if drop this ensure replot trains after replot routes else route will overwrite a train
18650  }
18651  }
18652  if(Track->RouteFlashFlag && Display->ZoomOutFlag) // must have entered RouteFlash from normal screen so button states stored
18653  // dropped ZoomOutButton when route or point flashing, but leave this section in in case need to reinstate
18654  // no need to call Clearand... as that is called when revert to normal mode
18655  {
18656  if((Now - RouteFlashStartTime) >= TDateTime(RouteFlashDuration / 86400))
18657  {
18658  Track->RouteFlashFlag = false;
18659  if(PreferredRouteFlag)
18660  {
18662  }
18663  else
18664  {
18666  }
18667  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
18668  }
18669  }
18671  {
18672  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
18673  {
18674  // cancel if train is present on or enters a flashing point, either selected or diverging
18676  {
18678  Track->PointFlashFlag = false;
18680  Utilities->CallLogPop(76);
18681  return;
18682  }
18684  {
18686  Track->PointFlashFlag = false;
18688  Utilities->CallLogPop(77);
18689  return;
18690  }
18691  if(WarningFlash)
18692  {
18695  }
18696  else
18697  {
18699  }
18700  }
18701  else
18702  {
18707  {
18711  }
18713  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
18714  Track->PointFlashFlag = false;
18716  }
18717  }
18719  // dropped ZoomOutButton when point flashing but leave this section in in case need to reinstate
18720  {
18721  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
18722  {
18726  {
18729  }
18730  Track->PointFlashFlag = false;
18732  }
18733  }
18734 // deal with changing level crossings
18735  if(!Track->ChangingLCVector.empty() && (Level2OperMode != Paused))
18736  {
18737  int H;
18738  int V;
18739 
18740  for(unsigned int x = 0; x < Track->ChangingLCVector.size(); x++)
18741  {
18742  bool Manual = false;
18743  if(Track->ChangingLCVector.at(x).TypeOfRoute == 2) // manual
18744  {
18745  Manual = true;
18746  }
18747  H = Track->ChangingLCVector.at(x).HLoc;
18748  V = Track->ChangingLCVector.at(x).VLoc;
18749  if((Now - Track->ChangingLCVector.at(x).StartTime) < TDateTime((Track->ChangingLCVector.at(x).ChangeDuration) / 86400))
18750  // still flashing
18751  {
18752  if(WarningFlash)
18753  {
18754  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising) // closing to trains
18755  {
18756  Track->PlotRaisedLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
18757 // always plots red when raising
18758  }
18759  else
18760  {
18761  Track->PlotLoweredLinkedLevelCrossingBarriers(0, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
18762  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
18763  }
18764  }
18765  else
18766  {
18767  Track->PlotLCBaseElementsOnly(2, Track->ChangingLCVector.at(x).BarrierState, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
18768  Track->ChangingLCVector.at(x).TypeOfRoute, Display);
18769  }
18770  }
18771  else
18772  // flashing period finished
18773  {
18774  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising)
18775  {
18776  Track->PlotRaisedLinkedLevelCrossingBarriers(2, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
18777 // always plot red when fully raised
18778  Track->SetLinkedLevelCrossingBarrierAttributes(4, H, V, 0); // only set attr to 0 when fully raised
18779  // attributes set to 2 when changing state, now reset to 0, no other actions needed
18780  }
18781  else
18782  // barriers lowering
18783  {
18784  Track->PlotLoweredLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
18785  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
18786  Track->SetLinkedLevelCrossingBarrierAttributes(5, H, V, 1); // only set attr to 1 when fully lowered
18787  bool FoundFlag;
18788  int TVPos = Track->GetVectorPositionFromTrackMap(46, H, V, FoundFlag);
18789  if(!FoundFlag)
18790  {
18791  throw Exception("Failed to find a route at LC position HLoc = " + (AnsiString)H + " VLoc = " + (AnsiString)V);
18792  }
18793  int RouteNumber;
18794  AllRoutes->GetRouteTypeAndNumber(24, TVPos, 0, RouteNumber); // use 0 for LinkPos, could be 1 or 0 as only a single track element
18795  // don't need returned value of RouteType
18796  if(RouteNumber > -1) // if train crashed then there won't be a routenumber
18797  {
18798  AllRoutes->GetFixedRouteAt(196, RouteNumber).SetRouteSignals(8);
18799  }
18800  }
18801  }
18802  }
18803  for(int x = Track->ChangingLCVector.size() - 1; x >= 0; x--)
18804  {
18805  // now transfer lowering barrier object from the ChangingLCVector to the BarriersDownVector if lowering, reset the start timer (to time the barrier down period)
18806  // and for either raising or lowering erase the object from the ChangingLCVector
18807  if(!Track->IsLCBarrierFlashingAtHV(0, Track->ChangingLCVector.at(x).HLoc, Track->ChangingLCVector.at(x).VLoc))
18808  {
18809  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Lowering)
18810  {
18811  Track->ChangingLCVector.at(x).StartTime = TrainController->TTClockTime;
18812  Track->ChangingLCVector.at(x).BarrierState = TTrack::Down;
18813  Track->BarriersDownVector.push_back(Track->ChangingLCVector.at(x));
18814  }
18815  Track->ChangingLCVector.erase(Track->ChangingLCVector.begin() + x);
18816  }
18817  }
18818  }
18819  Utilities->CallLogPop(747);
18820 }
18821 
18822 // ---------------------------------------------------------------------------
18823 
18825 // set boundary, Home, NewHome, ZoomOut, CallingOn buttons & menu items as appropriate
18826 {
18827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetSaveMenuAndButtons");
18828 
18829 // set save railway buttons
18830  bool SaveRailwayButtonsFlag = true;
18831 
18832  SaveRailwayTBPButton->Visible = true;
18833  SaveRailwayPDPButton->Visible = true;
18834  SaveSessionButton->Visible = true;
18835  if(Level1Mode == OperMode)
18836  {
18838  {
18839  SaveRailwayButtonsFlag = false;
18840  }
18841  // set PresetAutoSigRoutesButton enabled or not
18842  // enable if PreStart & no routes set
18843  if((Level2OperMode == PreStart) && (AllRoutes->AllRoutesVector.empty()) && !EveryPrefDir->PrefDirVector.empty())//last condition added at v2.10.0
18844  {
18845  PresetAutoSigRoutesButton->Enabled = true;
18846  }
18847  else
18848  {
18849  PresetAutoSigRoutesButton->Enabled = false;
18850  }
18851  }
18852  else
18853  {
18855  && Track->UserGraphicVector.empty()))
18856  {
18857  SaveRailwayButtonsFlag = false;
18858  }
18859  else if(SavedFileName != "")
18860  {
18861  if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
18862  {
18863  if(!(Track->IsReadyForOperation(false)))
18864  {
18865  SaveRailwayButtonsFlag = false; // can't save under its old name as not now a .rly file
18866  }
18867  }
18868  }
18869  }
18870  if(SaveRailwayButtonsFlag && (Level1Mode == BaseMode))
18871  {
18872  SaveRailwayBaseModeButton->Visible = true;
18873  }
18874  else
18875  {
18876  SaveRailwayBaseModeButton->Visible = false;
18877  }
18878  SaveRailwayTBPButton->Enabled = SaveRailwayButtonsFlag;
18879  SaveRailwayPDPButton->Enabled = SaveRailwayButtonsFlag;
18880  SaveRailwayBaseModeButton->Enabled = SaveRailwayButtonsFlag;
18881  SaveSessionButton->Enabled = SaveRailwayButtonsFlag;
18882 
18883 // set formatted timetable menu item
18884  if(TimetableTitle == "")
18885  {
18886  ExportTTMenuItem->Enabled = false;
18887  }
18888  else
18889  {
18890  ExportTTMenuItem->Enabled = true;
18891  }
18892 // set info menu items
18894  {
18895  FloatingInfoMenu->Enabled = false;
18896  TrackInfoMenuItem->Enabled = false;
18897  TrainInfoMenuItem->Enabled = false;
18898  }
18899  else
18900  {
18901  FloatingInfoMenu->Enabled = true;
18902  TrackInfoMenuItem->Enabled = true;
18903  if(Level1Mode == OperMode)
18904  {
18905  TrainInfoMenuItem->Enabled = true;
18906  }
18907  else
18908  {
18909  TrainInfoMenuItem->Enabled = false;
18910  }
18911  }
18912 // set all bar CallingOnButton operational to begin with - no, causes flickering of button graphics,
18913 // work on internal flags & then set buttons according to final flag values, then graphic won't change unless
18914 // there has been a legitimate change of state since the last access
18915 
18916  bool ZoomFlag = true, HomeFlag = true, NewHomeFlag = true, ScreenLeftFlag = true, ScreenRightFlag = true, ScreenUpFlag = true, ScreenDownFlag = true,
18917  TrackBuildPanelEnabledFlag = true, PrefDirPanelEnabledFlag = true, OperatingPanelEnabledFlag = true, TimetablePanelEnabledFlag = true;
18918 
18919  AnsiString TrackBuildPanelLabelCaptionStr = "Build/modify";
18920  AnsiString PrefDirPanelLabelCaptionStr = "Preferred direction selection";
18921  AnsiString OperatingPanelLabelCaptionStr = "Operation";
18922  AnsiString TimetablePanelLabelCaptionStr = "Timetable editor";
18923 
18924  if(!Display->ZoomOutFlag)
18925  {
18926  // prevent if half a screen or less visible (width = 60, height = 36) [Note HLocMin & Max 1 greater than extreme element]
18928  {
18929  ScreenLeftFlag = false; // 60 - 30
18930  }
18932  {
18933  ScreenRightFlag = false; // 60 - (60 - 30)
18934  }
18936  {
18937  ScreenUpFlag = false; // 36 - 18
18938  }
18940  {
18941  ScreenDownFlag = false; // 36 - (36 - 18)
18942  }
18943  }
18944  else
18945  {
18946  // prevent if less than a quarter of a screen visible (width = 240, height = 144)
18948  {
18949  ScreenLeftFlag = false; // 240 - 60
18950  }
18952  {
18953  ScreenRightFlag = false; // 240 - (240 - 60)
18954  }
18956  {
18957  ScreenUpFlag = false; // 144 - 36
18958  }
18960  {
18961  ScreenDownFlag = false; // 144 - (144 - 36)
18962  }
18963  }
18965  {
18966  ZoomFlag = false;
18967  HomeFlag = false;
18968  NewHomeFlag = false;
18969  ScreenLeftFlag = false;
18970  ScreenRightFlag = false;
18971  ScreenUpFlag = false;
18972  ScreenDownFlag = false;
18973  }
18974  if(Display->ZoomOutFlag)
18975  {
18976 // NewHomeFlag = false;
18977  TrackBuildPanelEnabledFlag = false;
18978  TrackBuildPanelLabelCaptionStr = "Disabled";
18979  PrefDirPanelEnabledFlag = false;
18980  PrefDirPanelLabelCaptionStr = "Disabled";
18981  OperatingPanelEnabledFlag = false;
18982  OperatingPanelLabelCaptionStr = "Disabled";
18983  TimetablePanelEnabledFlag = false;
18984  TimetablePanelLabelCaptionStr = "Disabled";
18985  }
18986  if(Level1Mode == OperMode)
18987  {
18988  if(Track->RouteFlashFlag || Track->PointFlashFlag || TTClockAdjPanel->Visible == true || TTClockAdjustWarningPanel->Visible == true ||
18989  MultiplayerHostPanel->Visible == true || MultiplayerPlayerPanel->Visible == true || SkipTTActionsListBox->Visible)
18990  // TTClockAdjPanel added for v2.4.2 to keep it disabled after Clock2Stopped dropped
18991  // host & player panels added for multiplayer
18992  {
18993  MTBFEditBox->Enabled = false;
18994  OperatingPanelEnabledFlag = false;
18995  OperatingPanelLabelCaptionStr = "Disabled";
18996  ZoomFlag = false;
18997  HomeFlag = false;
18998  NewHomeFlag = false;
18999  ScreenLeftFlag = false;
19000  ScreenRightFlag = false;
19001  ScreenUpFlag = false;
19002  ScreenDownFlag = false;
19003  SaveOperatingImageMenuItem->Enabled = false;
19004  }
19005  else
19006  {
19007  MTBFEditBox->Enabled = true;
19008  SaveOperatingImageMenuItem->Enabled = true;
19009  }
19010  }
19011  if(LocationNameTextBox->Visible)
19012  {
19013  ZoomFlag = false;
19014  HomeFlag = false;
19015  NewHomeFlag = false;
19016  ScreenLeftFlag = false;
19017  ScreenRightFlag = false;
19018  ScreenUpFlag = false;
19019  ScreenDownFlag = false;
19020  }
19021  if(TextBox->Visible) // added at v1.3.0 to prevent screen moving when movement keys pressed during text entry
19022  {
19023  ZoomFlag = false;
19024  HomeFlag = false;
19025  NewHomeFlag = false;
19026  ScreenLeftFlag = false;
19027  ScreenRightFlag = false;
19028  ScreenUpFlag = false;
19029  ScreenDownFlag = false;
19030  }
19031  if((Level1Mode == TimetableMode) && (TimetableEditPanel->Visible))
19032  // added at v1.3.0 to prevent screen moving when movement keys pressed during timetable compilation (allowed if TT hidden)
19033  {
19034  ZoomFlag = false;
19035  HomeFlag = false;
19036  NewHomeFlag = false;
19037  ScreenLeftFlag = false;
19038  ScreenRightFlag = false;
19039  ScreenUpFlag = false;
19040  ScreenDownFlag = false;
19041  }
19044  {
19045  ZoomFlag = false;
19046  }
19047  if(ZoomFlag)
19048  {
19049  ZoomButton->Enabled = true;
19050  }
19051  else
19052  {
19053  ZoomButton->Enabled = false;
19054  }
19055  if(HomeFlag)
19056  {
19057  HomeButton->Enabled = true;
19058  }
19059  else
19060  {
19061  HomeButton->Enabled = false;
19062  }
19063  if(NewHomeFlag)
19064  {
19065  NewHomeButton->Enabled = true;
19066  }
19067  else
19068  {
19069  NewHomeButton->Enabled = false;
19070  }
19071  if(ScreenLeftFlag)
19072  {
19073  ScreenLeftButton->Enabled = true;
19074  }
19075  else
19076  {
19077  ScreenLeftButton->Enabled = false;
19078  }
19079  if(ScreenRightFlag)
19080  {
19081  ScreenRightButton->Enabled = true;
19082  }
19083  else
19084  {
19085  ScreenRightButton->Enabled = false;
19086  }
19087  if(ScreenUpFlag)
19088  {
19089  ScreenUpButton->Enabled = true;
19090  }
19091  else
19092  {
19093  ScreenUpButton->Enabled = false;
19094  }
19095  if(ScreenDownFlag)
19096  {
19097  ScreenDownButton->Enabled = true;
19098  }
19099  else
19100  {
19101  ScreenDownButton->Enabled = false;
19102  }
19103  if(OperatingPanelEnabledFlag)
19104  {
19105  OperatingPanel->Enabled = true;
19106  }
19107  else
19108  {
19109  OperatingPanel->Enabled = false;
19110  }
19111  if(TrackBuildPanelEnabledFlag)
19112  {
19113  TrackBuildPanel->Enabled = true;
19114  }
19115  else
19116  {
19117  TrackBuildPanel->Enabled = false;
19118  }
19119  if(PrefDirPanelEnabledFlag)
19120  {
19121  PrefDirPanel->Enabled = true;
19122  }
19123  else
19124  {
19125  PrefDirPanel->Enabled = false;
19126  }
19127  if(TimetablePanelEnabledFlag)
19128  {
19129  TimetablePanel->Enabled = true;
19130  }
19131  else
19132  {
19133  TimetablePanel->Enabled = false;
19134  }
19135  TrackBuildPanelLabel->Caption = TrackBuildPanelLabelCaptionStr;
19136  PrefDirPanelLabel->Caption = PrefDirPanelLabelCaptionStr;
19137  OperatingPanelLabel->Caption = OperatingPanelLabelCaptionStr;
19138  TimetablePanelLabel->Caption = TimetablePanelLabelCaptionStr;
19139 
19140 // check if any CallingOnFlags set & set button accordingly
19141  if(Display->ZoomOutFlag)
19142  {
19143  CallingOnButton->Enabled = false;
19144  CallingOnButton->Down = false;
19145  }
19146  else
19147  {
19148  if(Level2OperMode == Operating)
19149  {
19150  bool CallOnValid = false;
19151  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
19152  {
19154  {
19155  CallingOnButton->Enabled = true;
19156  CallOnValid = true;
19157  }
19158  }
19159  if(!CallOnValid)
19160  {
19161  CallingOnButton->Enabled = false;
19162  CallingOnButton->Down = false;
19163  }
19164  }
19165  else
19166  {
19167  CallingOnButton->Enabled = false;
19168  CallingOnButton->Down = false;
19169  }
19170  }
19171  Utilities->CallLogPop(970);
19172 }
19173 
19174 // ---------------------------------------------------------------------------
19175 
19176 void TInterface::ErrorLog(int Caller, AnsiString Message)
19177 {
19178 // create an error file for diagnostic purposes called on detection of a runtime error
19179 
19180 // Note: For faults in ClockTimer2, after the catch block in ClockTimer2 which calls this function, execution continues from where
19181 // ClockTimer2 was called, so the Utilities->Clock2Stopped flag is cleared and the whole sequence repeats itself, including the fault, until
19182 // the user presses the Exit button. Note also that Utilities->CallLogPop, called when ClockTimer (not ClockTimer2) returns, pops the error
19183 // message off the back of the Utilities->CallLog, not the ClockTimer call. Hence entries keep stacking up, including the push_front entry
19184 // but not the push_back error entry, and when finally printed there is a whole series of entries for the one fault, the number
19185 // depending on the time taken to press Exit.
19186 // Hence introduce an ErrorLogCalledFlag, set to true on first call, and preventing further calls thereafter.
19187 
19188  if(ErrorLogCalledFlag)
19189  {
19190  return;
19191  }
19192  ErrorLogCalledFlag = true;
19193  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + "," + Message);
19194  Utilities->CallLog.push_front("Version: " + ProgramVersion + "; Time and date: " + Utilities->DateTimeStamp());
19195  SaveErrorFile();
19196  if((TempTTFileName != "") && FileExists(TempTTFileName))
19197  {
19198  DeleteFile(TempTTFileName);
19199  }
19200  Display->GetImage()->Visible = false;
19201  PerformancePanel->Visible = false;
19202  OperatorActionPanel->Visible = false; // new v2.2.0
19203  TrackBuildPanel->Visible = false;
19204  TrackElementPanel->Visible = false;
19205  LocationNameTextBox->Visible = false;
19206  TextBox->Visible = false;
19207  TrackLengthPanel->Visible = false;
19208  InfoPanel->Visible = false;
19209  PrefDirPanel->Visible = false;
19210  TimetablePanel->Visible = false;
19211  TimetableEditPanel->Visible = false;
19212  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
19213  OperatingPanel->Visible = false;
19214  FloatingPanel->Visible = false;
19215  ModeMenu->Enabled = false;
19216  SigImagePanel->Visible = false; // new at v2.3.0
19217  FileMenu->Enabled = false;
19218  EditMenu->Enabled = false;
19219  FloatingInfoMenu->Enabled = false;
19220  HelpMenu->Enabled = false;
19221 // SaveHeaderMenu1->Enabled = false;
19222  ScreenLeftButton->Visible = false;
19223  ScreenRightButton->Visible = false;
19224  ScreenUpButton->Visible = false;
19225  ScreenDownButton->Visible = false;
19226  HomeButton->Visible = false;
19227  NewHomeButton->Visible = false;
19228  ZoomButton->Visible = false;
19229  PrefDirKey->Visible = false;
19230  DistanceKey->Visible = false;
19231  RecoverClipboardMessageSent = true; // to stop paste message being given if recover clipboard error
19232  OutputLog1->Caption = "";
19233  OutputLog2->Caption = "";
19234  OutputLog3->Caption = "";
19235  OutputLog4->Caption = "";
19236  OutputLog5->Caption = "";
19237  OutputLog6->Caption = "";
19238  OutputLog7->Caption = "";
19239  OutputLog8->Caption = "";
19240  OutputLog9->Caption = "";
19241  OutputLog10->Caption = "";
19242  if(Caller == 113)
19243  {
19244  ErrorMessageStoreImage->Visible = true;
19245  }
19246  else
19247  {
19248  ErrorMessage->Visible = true;
19249  }
19250  ErrorButton->Visible = true;
19251  Screen->Cursor = TCursor(-2); // Arrow; - in case was an hourglass
19252 // No need for Utilities->CallLogPop as the call log deque has already been written to file & the next action
19253 // is to close the program when the exit button is pressed
19254 }
19255 
19256 // ---------------------------------------------------------------------------
19257 
19259 // not used from v2.2.0 as now allow floating panel & label to overlie performance panel
19260 {
19261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPerformancePanelObscuringFloatingLabel");
19262  if(FloatingPanel->Visible == false)
19263  {
19264  Utilities->CallLogPop(1205);
19265  return(false);
19266  }
19267 // pptop >= flbot, ppbot <= fltop, ppleft >= flright, ppright <= flleft
19268  if((PerformancePanel->Top >= (FloatingPanel->Top + FloatingPanel->Height)) || ((PerformancePanel->Top + PerformancePanel->Height) <= FloatingPanel->Top) ||
19269  (PerformancePanel->Left >= (FloatingPanel->Left + FloatingPanel->Width)) || ((PerformancePanel->Left + PerformancePanel->Width) <= FloatingPanel->Left))
19270  {
19271  Utilities->CallLogPop(1206);
19272  return(false);
19273  }
19274  else
19275  {
19276  Utilities->CallLogPop(1207);
19277  return(true);
19278  }
19279 }
19280 // ---------------------------------------------------------------------------
19281 
19282 void TInterface::SetCaption(int Caller)
19283 {
19284 /*
19285  NamedRailway; RlyFile; NamedTimetable
19286  n x x "New railway under development";
19287  y n x RailwayTitle + ": under development";
19288  y y n RailwayTitle + ": no timetable loaded";
19289  y y y RailwayTitle + ", " + TimetableTitle;
19290 */
19291 
19292  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetCaption");
19293  if(RailwayTitle == "")
19294  {
19295  Caption = "Railway: New railway under development";
19296  }
19297  else if(!RlyFile)
19298  {
19299  Caption = "Railway: " + RailwayTitle + " under development";
19300  }
19301 // else if(TimetableTitle == "") Caption = "Railway: " + RailwayTitle + "; Timetable: none loaded";
19302  else if(TimetableTitle == "")
19303  {
19304  Caption = "Railway: " + RailwayTitle; // changed at v2.1.0, no need to mention TT if none loaded
19305  }
19306  else
19307  {
19308  Caption = "Railway: " + RailwayTitle + "; Timetable: " + TimetableTitle;
19309  }
19310  session_api_->dump(); // update session INI file //added at v2.10.0
19311  Utilities->CallLogPop(1208);
19312 }
19313 
19314 // ---------------------------------------------------------------------------
19315 
19316 void TInterface::ResetAll(int Caller)
19317 {
19318  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAll");
19319  LastNonCtrlOrShiftKeyDown = -1; // added at v2.4.2 to no key down
19321  Track->GapFlashRedPosition = -1;
19322  Track->GapFlashFlag = false;
19323  Track->RouteFlashFlag = false;
19324  Track->PointFlashFlag = false;
19326  AutoSigsFlag = false;
19327  PreventGapOffsetResetting = false;
19328 
19329  Utilities->Clock2Stopped = false;
19330  TTClockSpeed = 1;
19331  TTClockSpeedLabel->Caption = "x1";
19332  Track->SetTrackFinished(false);
19334  CurrentSpeedButton = 0; // not assigned yet
19336  StartX = 0;
19337  StartY = 0;
19338  mbLeftDown = false;
19340  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
19342  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
19344  WarningFlashCount = 0;
19345 
19346  Level1Mode = BaseMode;
19347  SetLevel1Mode(26);
19348  RouteMode = None;
19349  PreferredRoute = true; // default starting conditions
19350  ConsecSignalsRoute = true; // default starting conditions
19351  DevelopmentPanel->Visible = false;
19352 
19353  MainScreen->Canvas->CopyMode = cmSrcCopy;
19354  FloatingPanel->Visible = false;
19355  OverallDistance = 0;
19356  OverallSpeedLimit = -1;
19357  AllRoutes->RouteTruncateFlag = false;
19358  CallingOnButton->Down = false;
19359  Display->ZoomOutFlag = false;
19360  ScreenGridFlag = false;
19361  InfoCaptionStore = "";
19362  ErrorLogCalledFlag = false;
19363  ErrorMessage->Visible = false;
19364  ErrorMessageStoreImage->Visible = false;
19365  TempCursorSet = false;
19366  TempCursor = TCursor(-2); // Arrow
19367  WholeRailwayMoving = false; // new at v2.1.0
19368 
19369  TrainController->TTClockTime = TDateTime(0); // default setting
19370  TTClockAdjPanel->Visible = false;
19372  ConflictPanel->Visible = false;
19373  SelectedTrainID = -1;
19374  SetTrackBuildImages(11);
19375 // TrackInfoOnOffMenuItem->Caption = "Show"; dropped these here at v1.2.0 so don't reset when load a session file
19376 // TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
19377 // TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
19378  Track->CalcHLocMinEtc(8);
19379  FileChangedFlag = false;
19380  RlyFile = false;
19381  SaveSessionFlag = false;
19382  LoadSessionFlag = false;
19383  SelectionValid = false;
19384  TimetableChangedFlag = false;
19385  SavedFileName = "";
19386  RailwayTitle = "";
19387  TimetableTitle = "";
19388  SetCaption(1);
19389  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
19390  // added for Beta v0.2b
19391  CreateEditTTTitle = ""; // as above
19392  AllRoutes->NextRouteID = 0;
19393  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
19394  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
19395 
19396  TempFont->Style.Clear();
19397  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
19398  TempFont->Size = 10;
19399  TempFont->Color = clB0G0R0;
19400  TempFont->Charset = (TFontCharset)(0);
19401  MainScreen->Canvas->Font->Assign(TempFont);
19402  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
19403  PerformancePanel->Left = MainScreen->Left;
19404  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new v2.2.0
19405  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
19406  ; // new v2.2.0
19407  // ScreenRightButton->Left = MainScreen->Width + MainScreen->Left; //Button values changed at v2.1.0 to allow for screen resizing
19408  // ScreenLeftButton->Left = ScreenRightButton->Left;
19409  // ScreenUpButton->Left = ScreenRightButton->Left;
19410  // ScreenDownButton->Left = ScreenRightButton->Left;
19411  // HomeButton->Left = ScreenRightButton->Left;
19412  // NewHomeButton->Left = ScreenRightButton->Left;
19413  // ZoomButton->Left = ScreenRightButton->Left;
19414  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height;
19415  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width;
19416  ; // new v2.2.0
19417 
19418  delete TempFont;
19419  CtrlKey = false;
19420  ShiftKey = false;
19421  ClipboardChecked = false;
19422  session_api_->dump(); // update session INI file //added at v2.10.0
19423  Utilities->CallLogPop(1209);
19424 }
19425 
19426 // ---------------------------------------------------------------------------
19427 
19429 {
19430  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackBuildImages,");
19431  if((Level1Mode == OperMode) || RlyFile)
19432  {
19433  TrackLinkedImage->Visible = false;
19434  TrackNotLinkedImage->Visible = false;
19435  GapsSetImage->Visible = false;
19436  GapsNotSetImage->Visible = false;
19437  LocationNamesSetImage->Visible = false;
19438  LocationNamesNotSetImage->Visible = false;
19439  Utilities->CallLogPop(1114);
19440  return;
19441  }
19442  else
19443  {
19444  if(!Track->NoActiveTrack(9))
19445  {
19446  if(Track->IsTrackFinished())
19447  {
19448  TrackLinkedImage->Visible = true;
19449  TrackNotLinkedImage->Visible = false;
19450  }
19451  else
19452  {
19453  TrackNotLinkedImage->Visible = true;
19454  TrackLinkedImage->Visible = false;
19455  }
19456  }
19457  else
19458  {
19459  TrackLinkedImage->Visible = false;
19460  TrackNotLinkedImage->Visible = false;
19461  }
19462  if(!Track->NoGaps(1))
19463  {
19464  if(Track->GapsUnset(6))
19465  {
19466  GapsNotSetImage->Visible = true;
19467  GapsSetImage->Visible = false;
19468  }
19469  else
19470  {
19471  GapsNotSetImage->Visible = false;
19472  GapsSetImage->Visible = true;
19473  }
19474  }
19475  else
19476  {
19477  GapsNotSetImage->Visible = false;
19478  GapsSetImage->Visible = false;
19479  }
19481  {
19482  if(Track->LocationsNotNamed(0))
19483  {
19484  LocationNamesSetImage->Visible = false;
19485  LocationNamesNotSetImage->Visible = true;
19486  }
19487  else
19488  {
19489  LocationNamesSetImage->Visible = true;
19490  LocationNamesNotSetImage->Visible = false;
19491  }
19492  }
19493  else
19494  {
19495  LocationNamesSetImage->Visible = false;
19496  LocationNamesNotSetImage->Visible = false;
19497  }
19498  }
19499  Utilities->CallLogPop(1113);
19500 }
19501 
19502 // ---------------------------------------------------------------------------
19503 
19504 void TInterface::ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
19505 {
19506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetChangedFileDataAndCaption");
19507  FileChangedFlag = true;
19508  if(NonPrefDirChangesMade)
19509  {
19510  if(RlyFile) // i.e. was a Railway file but major changes made so class as a new railway
19511  {
19512  RailwayTitle = "";
19513  TimetableTitle = "";
19514  SavedFileName = "";
19515  RlyFile = false;
19516  }
19517  TimetableTitle = ""; // should have been reset already during user mode change but include here also
19518  SetTrackBuildImages(15);
19519  }
19520  session_api_->dump(); // update session INI file //added at v2.10.0
19521  SetCaption(2);
19522  Utilities->CallLogPop(1210);
19523 }
19524 
19525 // ---------------------------------------------------------------------------
19526 
19527 void TInterface::SaveSession(int Caller)
19528 {
19529  // ExcessLCDownMins saved as string after ***Interface*** see below
19530  try
19531  {
19532  TrainController->LogEvent("SaveSession");
19533  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSession");
19534  AnsiString CurrentDateTimeStr = "", TimetableTimeStr = "", SessionFileStr = "";
19535  Screen->Cursor = TCursor(-11); // Hourglass;
19536  CurrentDateTimeStr = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
19537  // avoid characters in filename:= / \ : * ? " < > |
19538  TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
19539  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
19540 // SessionFileStr = CurDir + "\\" + SESSION_DIR_NAME + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
19541 // "; " + TimetableTitle + ".ssn";
19542  SessionFileStr = LoadSessionDialog->InitialDir + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
19543  "; " + TimetableTitle + ".ssn";
19544  std::ofstream SessionFile(SessionFileStr.c_str());
19545  if(!(SessionFile.fail()))
19546  {
19547  Utilities->SaveFileString(SessionFile, ProgramVersion + ": ***Interface***" + FloatToStr(TrainController->ExcessLCDownMins));
19548 // added ExcessLC... at v2.2.0 as omitted earlier
19549  SaveInterface(0, SessionFile);
19550  // save track elements
19551  Utilities->SaveFileString(SessionFile, "***Track***");
19552  if(Track->UserGraphicVector.empty())
19553  {
19554  Track->SaveTrack(4, SessionFile, false); // false for no graphics (**Active elements** saved as marker)
19555  }
19556  else
19557  {
19558  Track->SaveTrack(11, SessionFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
19559  }
19560  // save text elements
19561  Utilities->SaveFileString(SessionFile, "***Text***");
19562  TextHandler->SaveText(2, SessionFile);
19563  // save PrefDir elements
19564  Utilities->SaveFileString(SessionFile, "***PrefDirs***");
19565  EveryPrefDir->SavePrefDirVector(2, SessionFile);
19566  if(!Track->UserGraphicVector.empty())
19567  {
19568  // save user graphics
19569  Track->SaveUserGraphics(2, SessionFile);
19570  }
19571  // save routes
19572  Utilities->SaveFileString(SessionFile, "***Routes***");
19573  AllRoutes->SaveRoutes(0, SessionFile);
19574  // save LockedRoutes
19575  Utilities->SaveFileString(SessionFile, "***Locked routes***");
19576  TrainController->SaveSessionLockedRoutes(0, SessionFile);
19577  // save ContinuationAutoSigEntries
19578  Utilities->SaveFileString(SessionFile, "***ContinuationAutoSigEntries***");
19580  // save BarriersDownVector
19581  Utilities->SaveFileString(SessionFile, "***BarriersDownVector***");
19582  Track->SaveSessionBarriersDownVector(0, SessionFile);
19583  // save timetable
19584  Utilities->SaveFileString(SessionFile, "***Timetable***");
19585  if(!(SaveTimetableToSessionFile(0, SessionFile, SessionFileStr))) //includes the timetable itself + TrainOperatingData
19586  {
19587  SessionFile.close();
19588  DeleteFile(SessionFileStr);
19589  Screen->Cursor = TCursor(-2); // Arrow;
19590  TrainController->StopTTClockMessage(3, "Error saving file, unable to save session");
19591  Utilities->CallLogPop(1150);
19592  return;
19593  }
19594  // save TimetableClock
19595  Utilities->SaveFileString(SessionFile, "***TimetableClock***");
19596  Utilities->SaveFileDouble(SessionFile, double(TrainController->TTClockTime));
19597 
19598  // save trains
19599  Utilities->SaveFileString(SessionFile, "***Trains***");
19600  TrainController->SaveSessionTrains(0, SessionFile);
19601  // save performance file
19602  Utilities->SaveFileString(SessionFile, "***Performance file***");
19603  SavePerformanceFile(0, SessionFile);
19604  Utilities->SaveFileString(SessionFile, "***End of performance file***");
19605 
19606 /* The following additions are for later program versions where new features need to be saved in sessions.
19607 In each case need to ensure that the following points are considered and dealt with:
19608 
19609  1) New program works ok with old session files
19610  2) Old programs work ok with extended session file
19611  3) Check what happens to changed railway/track/trains/timetable etc when an old prog loads a new session file
19612  4) Ensure that the last character saved for a record change can't be 'E' as that used to identify the end of the additions
19613 */
19614  Utilities->SaveFileString(SessionFile, "***Additions after v2.3.1***");
19615 
19616 // additions at v2.4.0 to save TrainController->AvHoursIntValue
19619  Utilities->SaveFileString(SessionFile, "***Failed Trains***");
19620  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
19621  {
19623  {
19626  }
19627  }
19628  Utilities->SaveFileInt(SessionFile, -1); // marker for end of failed trains
19629  Utilities->SaveFileString(SessionFile, "End of file at v2.4.0");
19630 // end of v2.4.0 additions
19631 
19632 // addition at v2.7.0
19633  Utilities->SaveFileBool(SessionFile, ConsecSignalsRoute);
19634  Utilities->SaveFileString(SessionFile, "End of file at v2.7.0");
19635 // end of v2.7.0 addition
19636 
19637 // additions at v2.9.1
19641  Utilities->SaveFileDouble(SessionFile, double(TrainController->TotEarlyExitMins));
19642  Utilities->SaveFileDouble(SessionFile, double(TrainController->TotLateExitMins));
19643  Utilities->SaveFileString(SessionFile, "End of file at v2.9.1"); //changed from '2.9.0' at v2.9.2
19644 // end of v2.9.1 additions
19645 
19646 //additions at v2.11.0 - SkippedTTEvents
19648  // add data for trains in process of skipping timetable events (i.e. those with events after a future departure)
19649  if(!TrainController->TrainVector.empty())
19650  {
19651  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
19652  {
19653  TTrain Train = TrainController->TrainVectorAt(82, x);
19654  if(Train.SkippedDeparture)
19655  {
19656  Utilities->SaveFileInt(SessionFile, Train.TrainID);
19657  Utilities->SaveFileBool(SessionFile, Train.SkippedDeparture);
19658  Utilities->SaveFileBool(SessionFile, Train.ActionsSkippedFlag);
19659  Utilities->SaveFileInt(SessionFile, Train.SkipPtrValue);
19660  Utilities->SaveFileInt(SessionFile, Train.TrainSkippedEvents);
19661  }
19662  }
19663  }
19664  Utilities->SaveFileString(SessionFile, "End of file at v2.11.0");
19665 //end of v2.11.0 additions
19666 
19667 //additions at v2.12.0 - become new service early & treat pass as departure
19668  if(!TrainController->TrainVector.empty())
19669  {
19670  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
19671  {
19672  TTrain Train = TrainController->TrainVectorAt(85, x);
19673  if(Train.TreatPassAsTimeLocDeparture) //this can only apply once for a single train (service repeats are separate trains)
19674  {
19675  Utilities->SaveFileInt(SessionFile, Train.TrainID);
19676  }
19677  }
19678  }
19679  Utilities->SaveFileString(SessionFile, "End of file at v2.12.0");
19680 //end of v2.12.0 additions
19681 
19682 //additions at v2.13.0 - random location delays
19683  Utilities->SaveFileInt(SessionFile, Utilities->CumulativeDelayedRandMinsAllTrains); //to allow for exited and removed trains
19684 // Utilities->SaveFileInt(SessionFile, int(Utilities->DelayMode)); //restore mode on loading
19685  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
19686  { //if empty will skip
19687  TTrain Train = TrainController->TrainVectorAt(87, x);
19688  Utilities->SaveFileDouble(SessionFile, Train.NewDelay);
19689  Utilities->SaveFileDouble(SessionFile, Train.DelayedRandMins);
19691  Utilities->SaveFileDouble(SessionFile, double(Train.ActualArrivalTime));
19692  //ReleaseTime already loaded
19693  }
19694  Utilities->SaveFileString(SessionFile, "End of file at v2.13.0");
19695 //end of v2.13.0 additions
19696  SessionFile.close();
19697  TrainController->StopTTClockMessage(4, "Session saved: Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " +
19698  RailwayTitle + "; " + TimetableTitle + ".ssn");
19700 // to restore the ability to reselect Ctrl S after a save (FormKeyUp doesn't work because the Interface form doesn't have focus)
19701  }
19702  else
19703  {
19704  TrainController->StopTTClockMessage(5, "Session file failed to open - reason not known, unable to save.");
19705  }
19707  Screen->Cursor = TCursor(-2); // Arrow
19708  Utilities->CallLogPop(1141);
19709  }
19710  catch(const Exception &e) //non-error catch
19711  {
19712  TrainController->StopTTClockMessage(95, "Session file failed to save - reason not known.");
19713  Screen->Cursor = TCursor(-2); // Arrow;
19714  Utilities->CallLogPop(2440);
19715  }
19716 }
19717 
19718 // ---------------------------------------------------------------------------
19719 
19720 void TInterface::LoadSession(int Caller)
19721 // always loads in 'Paused' or 'PreStart' mode
19722 {
19723 // remember to load the timetable clock
19724 // no routes in build
19725 // prob need to set 'OperMode' then 'Paused', ensure have all info needed for these
19726 // set buttons enabled to correspond to flags on reloading. If no PrefDirs then disable all route buttons
19727 // set RlyFile true
19728  try
19729  {
19730  TrainController->LogEvent("LoadSession");
19731  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadSession");
19732  if(!ClearEverything(4))
19733  {
19734  Utilities->CallLogPop(1145);
19735  return;
19736  }
19737  LoadSessionDialog->Filter = "Session file (*.ssn)|*.ssn";
19738  if(LoadSessionDialog->Execute())
19739  {
19740  if(LoadSessionDialog->InitialDir != TPath::GetDirectoryName(LoadSessionDialog->FileName)) // new at v2.6.0 to retain a new directory
19741  {
19742  LoadSessionDialog->InitialDir = TPath::GetDirectoryName(LoadSessionDialog->FileName);
19743  }
19744  TrainController->LogEvent("LoadSession " + LoadSessionDialog->FileName);
19745  Screen->Cursor = TCursor(-11); // Hourglass;
19746  if(SessionFileIntegrityCheck(0, AnsiString(LoadSessionDialog->FileName).c_str()))
19747  // if(true)
19748  {
19749  std::ifstream SessionFile(AnsiString(LoadSessionDialog->FileName).c_str());
19750  if(!(SessionFile.fail()))
19751  {
19752  TrainController->AvHoursIntValue = 0; // initial value set at v2.4.0 in case not changed later
19753  TrainController->MTBFHours = 0; // initial value set at v2.4.0 in case not changed later
19754  AnsiString TempString = Utilities->LoadFileString(SessionFile);
19755 // "version + : ***Interface***" + at v2.2.0 ExcessLCDownMins (omitted earlier)
19756 
19757  int LastCharBeforeFloat = TempString.LastDelimiter('*'); // added at v2.2.0
19758  if((LastCharBeforeFloat == 0) || (LastCharBeforeFloat == TempString.Length()))
19759  // can't find it or no value for Excess LCDownMins, either way count as zero
19760  {
19762  }
19763  else
19764  {
19765  AnsiString FloatStr = TempString.SubString(LastCharBeforeFloat + 1, TempString.Length() - LastCharBeforeFloat);
19766  if(!Utilities->CheckStringDouble(FloatStr)) // returns false for empty string or invalid double
19767  {
19769  }
19770  else
19771  {
19772  TrainController->ExcessLCDownMins = FloatStr.ToDouble();
19773  }
19774  } // end of v2.2.0 * v2.4.0 additions
19775 
19776  LoadInterface(0, SessionFile);
19777  int TempDisplayOffsetH = Display->DisplayOffsetH; // stored as they are zeroed when track loaded
19778  int TempDisplayOffsetV = Display->DisplayOffsetV;
19779  int TempDisplayOffsetHHome = Display->DisplayOffsetHHome;
19780  int TempDisplayOffsetVHome = Display->DisplayOffsetVHome;
19781  bool GraphicsFollow = false;
19782  // load track elements
19783  TempString = Utilities->LoadFileString(SessionFile); // ***Track***"
19784  Track->LoadTrack(4, SessionFile, GraphicsFollow);
19785  // load text elements
19786  TempString = Utilities->LoadFileString(SessionFile); // ***Text***"
19787  TextHandler->LoadText(1, SessionFile);
19788  // load PrefDir elements
19789  TempString = Utilities->LoadFileString(SessionFile); // "***PrefDirs***"
19790  EveryPrefDir->LoadPrefDir(1, SessionFile);
19791  if(GraphicsFollow)
19792  {
19793  Track->LoadGraphics(1, SessionFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder);
19794  }
19796  {
19797  SessionFile.close();
19798  Screen->Cursor = TCursor(-2); // Arrow;
19799  ShowMessage("Corruption in preferred direction section of the session file, session can't be loaded");
19800  Utilities->CallLogPop(1438);
19801  return;
19802  }
19803  // load routes
19804  TempString = Utilities->LoadFileString(SessionFile); // "***Routes***"
19805  if(!AllRoutes->LoadRoutes(0, SessionFile))
19806  {
19807  SessionFile.close();
19808  Screen->Cursor = TCursor(-2); // Arrow;
19809  ShowMessage("Corruption in route section of the session file, session can't be loaded");
19810  Utilities->CallLogPop(1439);
19811  return;
19812  }
19813  // load LockedRoutes
19814  TempString = Utilities->LoadFileString(SessionFile); // "***Locked routes***"
19815  TrainController->LoadSessionLockedRoutes(0, SessionFile);
19816  // load ContinuationAutoSigEntries
19817  TempString = Utilities->LoadFileString(SessionFile); // "***ContinuationAutoSigEntries***"
19819  // load BarriersDownVector if present, but ensure backwards compatibility with earlier files
19820  TempString = Utilities->LoadFileString(SessionFile); // "***BarriersDownVector***" or "***Timetable***"
19821  if(TempString == "***BarriersDownVector***")
19822  {
19823  Track->LoadBarriersDownVector(0, SessionFile);
19824  TempString = Utilities->LoadFileString(SessionFile); // "***Timetable***"
19825  }
19826  // load timetable (marker "***Timetable***" already loaded)
19827  if(!(LoadTimetableFromSessionFile(0, SessionFile)))
19828  {
19829  SessionFile.close();
19830  Screen->Cursor = TCursor(-2); // Arrow;
19831  ShowMessage("Unable to load timetable section of the session file, session can't be loaded");
19832  Utilities->CallLogPop(1151);
19833  return;
19834  }
19835  // TimetableTitle should be loaded at this stage - check
19836  if(TimetableTitle == "")
19837  {
19838  SessionFile.close();
19839  Screen->Cursor = TCursor(-2); // Arrow;
19840  throw Exception("TimetableTitle null in LoadSession");
19841  }
19842  // load timetable clock
19843  TempString = Utilities->LoadFileString(SessionFile); // ***TimetableClock***
19844  TrainController->RestartTime = TDateTime(Utilities->LoadFileDouble(SessionFile)); // ClockTime set in RestartSessionOperMode;
19845  // load trains
19846  TempString = Utilities->LoadFileString(SessionFile); // ***Trains***
19847  TrainController->LoadSessionTrains(0, SessionFile);
19848  // load performance file + populate the performance log
19849  TempString = Utilities->LoadFileString(SessionFile); // ***Performance file***
19850  // first reset the performance file name and open it before reloading it
19851  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
19852  // avoid characters in filename:= / \ : * ? " < > |
19853  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " +
19854  TimetableTitle + ".txt";
19855  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
19856  if(Utilities->PerformanceFile.fail())
19857  {
19858  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
19859  " in the folder where the 'Railway.exe' program file resides");
19860  }
19861  // now reload the performance file
19862  LoadPerformanceFile(0, SessionFile);
19863 // addition at v2.4.0
19864  char TempChar;
19865  SessionFile.get(TempChar);
19866  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // get rid of all end of lines & emerge with eof or '*'
19867  {
19868  SessionFile.get(TempChar);
19869  }
19870  if(SessionFile.eof()) // end of file
19871  {
19874  SessionFile.close(); // no TrainController->AvHoursIntValue & no failed trains
19875  goto FINISHEDLOADING; //don't like goto's normally but necessary here to avoid multiple else's
19876  }
19877  { //remainder enclosed in a block so goto doesn't bypass initialisation of a local variable (DummyStr, ID etc.)
19878  AnsiString DummyStr = Utilities->LoadFileString(SessionFile); // "**Additions after v2.3.1***" discarded (first '*' loaded earlier)
19879  TrainController->AvHoursIntValue = Utilities->LoadFileInt(SessionFile); // TrainController->AvHoursIntValue added at v2.4.0
19880  TrainController->NumFailures = Utilities->LoadFileInt(SessionFile); // number of train failures
19881  TrainController->MTBFHours = TrainController->AvHoursIntValue; // TTClockSpeed set to 1 in RestartSessionMode so no need to include here
19882  // now load any failed trains along with their OriginalPowerAtRail values
19883  DummyStr = Utilities->LoadFileString(SessionFile); // discard "***Failed Trains***"
19884  int ID = Utilities->LoadFileInt(SessionFile); // train ID or -1 for no more failed trains
19885  double PowerDouble;
19886  while(ID != -1)
19887  {
19888  PowerDouble = Utilities->LoadFileDouble(SessionFile); // ok TrainVector loaded at this stage (loaded in LoadSessionTrains)
19891  ID = Utilities->LoadFileInt(SessionFile);
19892  }
19893 //end of 2.4.0 addition
19894 // addition at v2.7.0 - need value for ConsecSignalsRoute but might have eof here with older sessions so first test for that
19895  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.4.0" discarded
19896 
19897  SessionFile.get(TempChar);
19898  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // get rid of all end of lines & emerge with eof or '0' or '1'
19899  {
19900  SessionFile.get(TempChar);
19901  }
19902  if(SessionFile.eof())
19903  {
19904  SessionFile.close(); //ConsecSignalsRoute set to PrefDirRoute
19905  goto FINISHEDLOADING;
19906  }
19907  if((TempChar != '0') && (TempChar != '1'))
19908  {
19909  throw Exception("TempChar value = " + AnsiString(TempChar) + ", should be 0 or 1");
19910  }
19911  ConsecSignalsRoute = true;
19912  if(TempChar == '0')
19913  {
19914  ConsecSignalsRoute = false;
19915  // at v2.7.0 if find eof then don't need a value for ConsecSignalsRoute as that loaded during LoadInterface
19916  }
19917  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.7.0" discarded
19918 //end of 2.7.0 additions
19919 //additions at v2.9.1
19920  SessionFile.get(TempChar);
19921  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // get rid of all end of lines & emerge with 1st digit of EarlyExits as character
19922  {
19923  SessionFile.get(TempChar);
19924  }
19925  if(SessionFile.eof())
19926  {
19927  SessionFile.close();
19928  goto FINISHEDLOADING;
19929  }
19930  //TempChar now contains the first digit of EarlyExits as an ASCII character, so get the rest up to CRLF
19931  TempString = TempChar;
19932  SessionFile.get(TempChar);
19933  while((TempChar != '\n') && (TempChar != '\0'))
19934  {
19935  TempString = TempString + TempChar;
19936  SessionFile.get(TempChar);
19937  }
19938  TrainController->EarlyExits = TempString.ToInt();
19941  TrainController->TotEarlyExitMins = float(Utilities->LoadFileDouble(SessionFile));
19942  TrainController->TotLateExitMins = float(Utilities->LoadFileDouble(SessionFile));
19943  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.9.1" discarded
19944 //end of 2.9.1 additions
19945 
19946 //2.11.0 additions
19947  SessionFile.get(TempChar);
19948  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0')))
19949  {// get rid of all end of lines & emerge with eof or 1st digit of TrainController->SkippedTTEvents
19950  SessionFile.get(TempChar);
19951  }
19952  if(SessionFile.eof())
19953  {
19954  SessionFile.close();
19955  goto FINISHEDLOADING;
19956  }
19957  //TempChar now contains the first digit of SkippedTTEvents as a character, so get the rest up to CRLF
19958  TempString = TempChar;
19959  SessionFile.get(TempChar);
19960  while((TempChar != '\n') && (TempChar != '\0'))
19961  {
19962  TempString = TempString + TempChar;
19963  SessionFile.get(TempChar);
19964  }
19965  //here have SkippedTTEvents as AnsiString in TempString
19966  TrainController->SkippedTTEvents = TempString.ToInt();
19967  //now get the skip data for each train (may or may not be any)
19968  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0')))
19969  {// get rid of all end of lines & emerge with eof or 1st digit of TrainID
19970  SessionFile.get(TempChar);
19971  }
19972  if(SessionFile.eof())
19973  {
19974  SessionFile.close();
19975  goto FINISHEDLOADING;
19976  }
19977  //TempChar now contains the 1st digit of TrainID as a character or 'E'
19978  TempString = TempChar;
19979  while(TempString != 'E') //'E' is 1st character of 'End of file at v2.11.0'
19980  {
19981  SessionFile.get(TempChar);
19982  while((TempChar != '\n') && (TempChar != '\0'))
19983  {
19984  TempString = TempString + TempChar;
19985  SessionFile.get(TempChar);
19986  }
19987  //here have TrainID as AnsiString in TempString
19988  TTrain &Train = TrainController->TrainVectorAtIdent(57, TempString.ToInt());
19989  Train.SkippedDeparture = Utilities->LoadFileBool(SessionFile);
19990  Train.ActionsSkippedFlag = Utilities->LoadFileBool(SessionFile);
19991  Train.SkipPtrValue = Utilities->LoadFileInt(SessionFile);
19992  Train.TrainSkippedEvents = Utilities->LoadFileInt(SessionFile);
19993  SessionFile.get(TempChar); //will be '\n' as LoadFileInt doesn't extract newlines from the stream
19994  TempString = TempChar; //added at v2.12.0 as a safeguard in case not '\n' in which case it would retain its old value
19995  while((TempChar == '\n') || (TempChar == '\0')) //get rid of any excess non-significant chars
19996  {
19997  SessionFile.get(TempChar); //get the next one
19998  TempString = TempChar; //when emerge this will be 'E' or 1st digit of TrainID
19999  }
20000  }
20001  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.11.0" discarded ('E' already loaded)
20002 //end of 2.11.0 additions
20003 
20004 //additions at v2.12.0
20005  SessionFile.get(TempChar);
20006  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0')))
20007  {// get rid of all end of lines & emerge with eof or 1st digit of a TrainID or 'E'
20008  SessionFile.get(TempChar);
20009  }
20010  if(SessionFile.eof())
20011  {
20012  SessionFile.close();
20013  goto FINISHEDLOADING;
20014  }
20015  //TempChar now contains the first digit of the first train ID which requires TreatPassAsTimeLocDeparture to be set, or 'E' if none
20016  TempString = TempChar;
20017  while(TempString != 'E') //'E' is 1st character of 'End of file at v2.12.0'
20018  {
20019  SessionFile.get(TempChar);
20020  while((TempChar != '\n') && (TempChar != '\0'))
20021  {
20022  TempString = TempString + TempChar;
20023  SessionFile.get(TempChar);
20024  }
20025  //here have TrainID as AnsiString in TempString & '\n' in TempChar
20026  TTrain &Train = TrainController->TrainVectorAtIdent(62, TempString.ToInt());
20027  Train.TreatPassAsTimeLocDeparture = true;
20028  SessionFile.get(TempChar); //will be '\n' (if more than one) or 'E' or 1st digit of next TrainID as character
20029  TempString = TempChar;
20030  while((TempChar == '\n') || (TempChar == '\0')) //get rid of any excess non-significant chars, unlikely to be any
20031  {
20032  SessionFile.get(TempChar); //get the next one
20033  TempString = TempChar; //when emerge this will be 'E' or 1st digit of TrainID
20034  }
20035  }
20036  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.12.0" discarded ('E' already loaded)
20037 //end of additions at v2.12.0
20038 
20039 //additions at v2.13.0
20040  SessionFile.get(TempChar);
20041  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0')))
20042  {// get rid of all end of lines & emerge with eof or 1st digit of CumulativeDelayedRandMinsAllTrains
20043  SessionFile.get(TempChar);
20044  }
20045  if(SessionFile.eof())
20046  {
20047  SessionFile.close();
20048  goto FINISHEDLOADING;
20049  }
20050  //TempChar now contains the first digit of CumulativeDelayedRandMinsAllTrains
20051  TempString = "";
20052  while((TempChar != '\n') && (TempChar != '\0'))
20053  {
20054  TempString = TempString + TempChar;
20055  SessionFile.get(TempChar);
20056  }
20057  //here have CumulativeDelayedRandMinsAllTrains as AnsiString in TempString & '\n' in TempChar
20058  Utilities->CumulativeDelayedRandMinsAllTrains = TempString.ToDouble(); //if invalid will fail with a non-error catch
20059  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++) //trains already loaded, if no trains then load DummyStr
20060  { //if empty will skip
20061  double TempDouble;
20062  TTrain &Train = TrainController->TrainVectorAt(88, x);
20063  Train.NewDelay = Utilities->LoadFileDouble(SessionFile);
20064  Train.DelayedRandMins = Utilities->LoadFileDouble(SessionFile);
20066  TempDouble = Utilities->LoadFileDouble(SessionFile);
20067  Train.ActualArrivalTime = TDateTime(TempDouble); //ReleaseTime already loaded
20068  }
20069  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.13.0" discarded
20070 //end of additions at v2.13.0
20071 
20072  SessionFile.close();
20073  }
20074 
20075 FINISHEDLOADING:
20076  if(SessionFile.is_open())
20077  {
20078  SessionFile.close();
20079  }
20080  // deal with other settings
20081  Display->DisplayOffsetH = TempDisplayOffsetH; // reset to saved values
20082  Display->DisplayOffsetV = TempDisplayOffsetV;
20083  Display->DisplayOffsetHHome = TempDisplayOffsetHHome;
20084  Display->DisplayOffsetVHome = TempDisplayOffsetVHome;
20085  // now set attributes to 1 for all LCs with barriers down
20086  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
20087  {
20089  }
20090  Track->ChangingLCVector.clear();
20091  Track->CalcHLocMinEtc(10);
20093  SetLevel1Mode(27);
20094  if(Level2OperMode == PreStart)
20095  // this section added at v1.3.2 as otherwise only in MainScreenMouseDown2, and if load a session without clicking mouse on screen
20096  {
20097  // then delay unspecified though seems to be 0
20098  PointsFlashDuration = 0.0;
20101  }
20102  else
20103  {
20107  }
20108  RlyFile = true;
20109  SetCaption(3);
20111  }
20112  }
20113  else
20114  {
20115  ShowMessage("Session file integrity check failed, unable to load " + LoadSessionDialog->FileName);
20116  }
20117  Screen->Cursor = TCursor(-2); // Arrow;
20118  }
20119  Utilities->CallLogPop(1146);
20120  }
20121  catch(const Exception &e)
20122  {
20123  if((e.Message.Pos("esource") > 0) || (e.Message.Pos("arameter") > 0)) // 'Resource or Parameter, avoid capitals as may be OS dependent
20124  {
20125  Screen->Cursor = TCursor(-2); // Arrow;
20126  OutputLog1->Caption = "";
20127  OutputLog2->Caption = "";
20128  OutputLog3->Caption = "";
20129  OutputLog4->Caption = "";
20130  OutputLog5->Caption = "";
20131  OutputLog6->Caption = "";
20132  OutputLog7->Caption = "";
20133  OutputLog8->Caption = "";
20134  OutputLog9->Caption = "";
20135  OutputLog10->Caption = "";
20136  UnicodeString MessageStr =
20137  "Insufficient memory available to load the file, and partial load likely to be corrupt. Application will terminate. Try loading the session as the first action after reloading the program.";
20138 // UnicodeString MessageStr = "Last train loaded = " + UnicodeString(TrainController->LastTrainLoaded); //for debugging session train loading for many trains
20139  Application->MessageBox(MessageStr.c_str(), L"Out of memory", MB_OK | MB_ICONERROR);
20140  Application->Terminate();
20141  }
20142  else //non-error catch
20143  {
20144  TrainController->StopTTClockMessage(96, "Session file failed to load - may be corrupt.");
20145  Screen->Cursor = TCursor(-2); // Arrow;
20146  Utilities->CallLogPop(2441);
20147  }
20148  }
20149 }
20150 
20151 // ---------------------------------------------------------------------------
20152 
20153 void TInterface::SaveInterface(int Caller, std::ofstream &SessionFile)
20154 {
20155  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveInterface");
20156  if(Level2OperMode == PreStart)
20157  {
20158  Utilities->SaveFileString(SessionFile, AnsiString("PreStart"));
20159  }
20160  else
20161  {
20162  Utilities->SaveFileString(SessionFile, AnsiString("NotPreStart")); // covers both Paused & Operating
20163  }
20164  Utilities->SaveFileString(SessionFile, RailwayTitle);
20165  Utilities->SaveFileString(SessionFile, TimetableTitle);
20166  Utilities->SaveFileBool(SessionFile, PreferredRoute);
20167  Utilities->SaveFileBool(SessionFile, PreferredRoute);
20168 // changed at v2.7.0, was ConsecSignalsRoute here but if different to PreferredRoute (as can be from v2.7.0) then have
20169  Utilities->SaveFileBool(SessionFile, AutoSigsFlag);
20170 // error if try to load with an earlier prog version. ConsecSignalsRoute now moved to end of session file
20171  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetH);
20172  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetV);
20177  Utilities->SaveFileString(SessionFile, OutputLog1->Caption);
20178  Utilities->SaveFileString(SessionFile, OutputLog2->Caption);
20179  Utilities->SaveFileString(SessionFile, OutputLog3->Caption);
20180  Utilities->SaveFileString(SessionFile, OutputLog4->Caption);
20181  Utilities->SaveFileString(SessionFile, OutputLog5->Caption);
20182  Utilities->SaveFileString(SessionFile, OutputLog6->Caption);
20183  Utilities->SaveFileString(SessionFile, OutputLog7->Caption);
20184  Utilities->SaveFileString(SessionFile, OutputLog8->Caption);
20185  Utilities->SaveFileString(SessionFile, OutputLog9->Caption);
20186  Utilities->SaveFileString(SessionFile, OutputLog10->Caption);
20187 
20209  // ExcessLCDownMins saved after ***Interface*** at v2.2.0 (omitted in error earlier)
20210  Utilities->CallLogPop(1211);
20211 }
20212 
20213 // ---------------------------------------------------------------------------
20214 void TInterface::LoadInterface(int Caller, std::ifstream &SessionFile)
20215 {
20216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadInterface");
20217  AnsiString OpMode = Utilities->LoadFileString(SessionFile);
20218 
20219  if(OpMode == "PreStart")
20220  {
20222  }
20223  else
20224  {
20226  }
20227  RailwayTitle = Utilities->LoadFileString(SessionFile);
20228  SavedFileName = CurDir + "\\" + RAILWAY_DIR_NAME + "\\" + RailwayTitle + ".rly";
20229 
20230  TimetableTitle = Utilities->LoadFileString(SessionFile);
20231  PreferredRoute = Utilities->LoadFileBool(SessionFile);
20232  ConsecSignalsRoute = Utilities->LoadFileBool(SessionFile);
20233  AutoSigsFlag = Utilities->LoadFileBool(SessionFile);
20234  Display->DisplayOffsetH = Utilities->LoadFileInt(SessionFile);
20235  Display->DisplayOffsetV = Utilities->LoadFileInt(SessionFile);
20240  OutputLog1->Caption = Utilities->LoadFileString(SessionFile);
20241  OutputLog2->Caption = Utilities->LoadFileString(SessionFile);
20242  OutputLog3->Caption = Utilities->LoadFileString(SessionFile);
20243  OutputLog4->Caption = Utilities->LoadFileString(SessionFile);
20244  OutputLog5->Caption = Utilities->LoadFileString(SessionFile);
20245  OutputLog6->Caption = Utilities->LoadFileString(SessionFile);
20246  OutputLog7->Caption = Utilities->LoadFileString(SessionFile);
20247  OutputLog8->Caption = Utilities->LoadFileString(SessionFile);
20248  OutputLog9->Caption = Utilities->LoadFileString(SessionFile);
20249  OutputLog10->Caption = Utilities->LoadFileString(SessionFile);
20250 
20258  TrainController->LateDeps = Utilities->LoadFileInt(SessionFile);
20272  session_api_->dump(); // update session INI file //added at v2.10.0
20273  Utilities->CallLogPop(1212);
20274 }
20275 
20276 // ---------------------------------------------------------------------------
20277 
20278 bool TInterface::CheckInterface(int Caller, std::ifstream &SessionFile)
20279 {
20280  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckInterface");
20281 
20282  AnsiString OpMode = "";
20283 
20284  if(!Utilities->CheckAndReadFileString(SessionFile, OpMode))
20285  {
20286  Utilities->CallLogPop(1767);
20287  return(false);
20288  }
20289  else if((OpMode != "PreStart") && (OpMode != "NotPreStart"))
20290  {
20291  Utilities->CallLogPop(1768);
20292  return(false);
20293  }
20294  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // RailwayTitle
20295  {
20296  Utilities->CallLogPop(1213);
20297  return(false);
20298  }
20299  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // TimetableTitle
20300  {
20301  Utilities->CallLogPop(1214);
20302  return(false);
20303  }
20304  if(!Utilities->CheckFileBool(SessionFile))
20305  {
20306  Utilities->CallLogPop(1216);
20307  return(false);
20308  }
20309  if(!Utilities->CheckFileBool(SessionFile))
20310  {
20311  Utilities->CallLogPop(1217);
20312  return(false);
20313  }
20314  if(!Utilities->CheckFileBool(SessionFile))
20315  {
20316  Utilities->CallLogPop(1218);
20317  return(false);
20318  }
20319  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
20320  {
20321  Utilities->CallLogPop(1409);
20322  return(false);
20323  }
20324  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
20325  {
20326  Utilities->CallLogPop(1486);
20327  return(false);
20328  }
20329  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
20330  {
20331  Utilities->CallLogPop(1487);
20332  return(false);
20333  }
20334  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
20335  {
20336  Utilities->CallLogPop(1488);
20337  return(false);
20338  }
20339  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
20340  {
20341  Utilities->CallLogPop(1489);
20342  return(false);
20343  }
20344  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
20345  {
20346  Utilities->CallLogPop(1528);
20347  return(false);
20348  }
20349  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20350  {
20351  Utilities->CallLogPop(1725);
20352  return(false);
20353  }
20354  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20355  {
20356  Utilities->CallLogPop(1726);
20357  return(false);
20358  }
20359  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20360  {
20361  Utilities->CallLogPop(1727);
20362  return(false);
20363  }
20364  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20365  {
20366  Utilities->CallLogPop(1728);
20367  return(false);
20368  }
20369  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20370  {
20371  Utilities->CallLogPop(1730);
20372  return(false);
20373  }
20374  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20375  {
20376  Utilities->CallLogPop(1731);
20377  return(false);
20378  }
20379  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20380  {
20381  Utilities->CallLogPop(1732);
20382  return(false);
20383  }
20384  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20385  {
20386  Utilities->CallLogPop(1733);
20387  return(false);
20388  }
20389  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20390  {
20391  Utilities->CallLogPop(1734);
20392  return(false);
20393  }
20394  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
20395  {
20396  Utilities->CallLogPop(1789);
20397  return(false);
20398  }
20399  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20400  {
20401  Utilities->CallLogPop(1737);
20402  return(false);
20403  }
20404  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20405  {
20406  Utilities->CallLogPop(1738);
20407  return(false);
20408  }
20409  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20410  {
20411  Utilities->CallLogPop(1739);
20412  return(false);
20413  }
20414  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20415  {
20416  Utilities->CallLogPop(1740);
20417  return(false);
20418  }
20419  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20420  {
20421  Utilities->CallLogPop(1741);
20422  return(false);
20423  }
20424  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20425  {
20426  Utilities->CallLogPop(1742);
20427  return(false);
20428  }
20429  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20430  {
20431  Utilities->CallLogPop(1743);
20432  return(false);
20433  }
20434  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20435  {
20436  Utilities->CallLogPop(1744);
20437  return(false);
20438  }
20439  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20440  {
20441  Utilities->CallLogPop(1745);
20442  return(false);
20443  }
20444  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20445  {
20446  Utilities->CallLogPop(1746);
20447  return(false);
20448  }
20449  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20450  {
20451  Utilities->CallLogPop(1747);
20452  return(false);
20453  }
20454  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20455  {
20456  Utilities->CallLogPop(1748);
20457  return(false);
20458  }
20459  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20460  {
20461  Utilities->CallLogPop(1749);
20462  return(false);
20463  }
20464  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20465  {
20466  Utilities->CallLogPop(1750);
20467  return(false);
20468  }
20469  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20470  {
20471  Utilities->CallLogPop(1751);
20472  return(false);
20473  }
20474  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
20475  {
20476  Utilities->CallLogPop(1752);
20477  return(false);
20478  }
20479  if(!Utilities->CheckFileDouble(SessionFile))
20480  {
20481  Utilities->CallLogPop(1753);
20482  return(false);
20483  }
20484  if(!Utilities->CheckFileDouble(SessionFile))
20485  {
20486  Utilities->CallLogPop(1754);
20487  return(false);
20488  }
20489  if(!Utilities->CheckFileDouble(SessionFile))
20490  {
20491  Utilities->CallLogPop(1755);
20492  return(false);
20493  }
20494  if(!Utilities->CheckFileDouble(SessionFile))
20495  {
20496  Utilities->CallLogPop(1756);
20497  return(false);
20498  }
20499  if(!Utilities->CheckFileDouble(SessionFile))
20500  {
20501  Utilities->CallLogPop(1757);
20502  return(false);
20503  }
20504  Utilities->CallLogPop(1219);
20505  return(true);
20506 }
20507 
20508 // ---------------------------------------------------------------------------
20509 
20510 bool TInterface::SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
20511 {
20512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToSessionFile," + SessionFileStr);
20513  if(!FileExists(TempTTFileName))
20514  {
20515  Utilities->CallLogPop(1862);
20516  return(false);
20517  }
20518  SessionFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
20519  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
20520 
20521  int Handle = FileOpen(TempTTFileName, fmOpenRead);
20522  int Count = 0;
20523 
20524  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
20525  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
20526  // then, but nevertheless have 10 retries before giving message to be on safe side
20527  {
20528  Handle = FileOpen(TempTTFileName, fmOpenRead);
20529  Count++;
20530  Delay(1, 50); // 50mSec delay between tries
20531  if(Count > 10)
20532  {
20533  ShowMessage("Failed to open temporary timetable file. Unable to save the session");
20534  Utilities->CallLogPop(1221);
20535  return(false);
20536  }
20537  }
20538 
20539  char *Buffer = new char[10000];
20540  int BytesRead;
20541 
20542  while(true)
20543  {
20544  BytesRead = FileRead(Handle, Buffer, 10000);
20545  SessionFile.write(Buffer, BytesRead);
20546  if(BytesRead < 10000)
20547  {
20548  break;
20549  }
20550  }
20551  delete[]Buffer;
20552  FileClose(Handle);
20553 
20554  SessionFile.close(); // close & re-open in append & text out mode as before so can write text
20555  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
20556 
20557  Utilities->SaveFileString(SessionFile, "***End***"); // marker for end of timetable
20558 // now need to save the TrainOperatingData so can be loaded back into the timetable as is
20559  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.size());
20560  for(unsigned int x = 0; x < TrainController->TrainDataVector.size(); x++)
20561  {
20562  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size());
20563  for(unsigned int y = 0; y < TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size(); y++)
20564  {
20565  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID);
20566  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported));
20567  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry));
20568  }
20569  }
20570  Utilities->CallLogPop(1220);
20571  return(true);
20572 }
20573 
20574 // ---------------------------------------------------------------------------
20575 
20576 bool TInterface::SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
20577 {
20578  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToErrorFile," + ErrorFileStr + "," + TimetableFileName);
20579  if(!FileExists(TimetableFileName))
20580  {
20581  Utilities->CallLogPop(1863);
20582  return(false);
20583  }
20584  ErrorFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
20585  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
20586 
20587  int Handle = FileOpen(TimetableFileName, fmOpenRead);
20588  int Count = 0;
20589 
20590  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
20591  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
20592  // then, but nevertheless have 10 retries before giving message to be on safe side
20593  {
20594  Handle = FileOpen(TimetableFileName, fmOpenRead);
20595  Count++;
20596  Delay(5, 50); // 50mSec delay between tries
20597  if(Count > 10)
20598  {
20599  Utilities->CallLogPop(1835);
20600  return(false);
20601  }
20602  }
20603 
20604  char *Buffer = new char[10000];
20605  int BytesRead;
20606 
20607  while(true)
20608  {
20609  BytesRead = FileRead(Handle, Buffer, 10000);
20610  ErrorFile.write(Buffer, BytesRead);
20611  if(BytesRead < 10000)
20612  {
20613  break;
20614  }
20615  }
20616  delete[]Buffer;
20617  FileClose(Handle);
20618 
20619  ErrorFile.close(); // close & re-open in append & text out mode as before so can write text
20620  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
20621 
20622  Utilities->SaveFileString(ErrorFile, "***End of timetable***"); // marker for end of timetable
20623  Utilities->CallLogPop(1836);
20624  return(true);
20625 }
20626 
20627 // ---------------------------------------------------------------------------
20628 
20629 bool TInterface::LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
20630 // the .ttb section is delimited by "***End***"
20631 // create the temporary timetable file in the working folder exactly like the original
20632 {
20633  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTimetableFromSessionFile");
20634  // reset all message flags, stops them being given twice (shouldn't be needed here but add for safety) //new at v2.4.0
20635  TrainController->SSHigh = false;
20636  TrainController->MRSHigh = false;
20637  TrainController->MRSLow = false;
20638  TrainController->MassHigh = false;
20639  TrainController->BFHigh = false;
20640  TrainController->BFLow = false;
20641  TrainController->PwrHigh = false;
20642  TrainController->SigSHigh = false;
20643  TrainController->SigSLow = false;
20644  if((TempTTFileName != "") && FileExists(TempTTFileName))
20645  {
20646  DeleteFile(TempTTFileName);
20647  }
20648  int TempTTFileNumber = 0;
20649 
20650  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
20651  {
20652  TempTTFileNumber++;
20653  }
20654  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
20655 
20656  std::ofstream TTBFile(TempTTFileName.c_str()); // use text mode as SessionFile is in text mode, so CRLFs read as LFs, and LFs write as CRLFs.
20657  int Count;
20658  char Zero = '\0';
20659 
20660  if(!TTBFile.fail())
20661  {
20662  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
20663  char TempChar = (char)(SessionFile.peek()); // have a look at the next character, if it's '\n'
20664  if(TempChar == '\n')
20665  {
20666  SessionFile.get(TempChar); // then get rid of it, else leave it in as part of the first line
20667  }
20668  if(!SessionFile.getline(Buffer, 10000, '\0'))
20669  {
20670  TTBFile.close();
20671  DeleteFile(TempTTFileName);
20672  delete[]Buffer;
20673  Utilities->CallLogPop(1222);
20674  return(false);
20675  }
20676  Count = 0;
20677  for(int x = 0; x < 10000; x++)
20678  {
20679  if(Buffer[x] != '\0')
20680  {
20681  Count++;
20682  }
20683  else
20684  {
20685  break;
20686  }
20687  }
20688  while(AnsiString(Buffer) != "***End***")
20689  {
20690  TTBFile.write(Buffer, Count);
20691  TTBFile.write(&Zero, 1);
20692 // TTBFile.write(&NewLine, 1);
20693  if(!SessionFile.getline(Buffer, 10000, '\0'))
20694  {
20695  TTBFile.close();
20696  DeleteFile(TempTTFileName);
20697  delete[]Buffer;
20698  Utilities->CallLogPop(1223);
20699  return(false);
20700  }
20701  Count = 0;
20702  for(int x = 0; x < 10000; x++)
20703  {
20704  if(Buffer[x] != '\0')
20705  {
20706  Count++;
20707  }
20708  else
20709  {
20710  break;
20711  }
20712  }
20713  }
20714  TTBFile.close();
20715  delete[]Buffer;
20716 // SaveTempTimetableFile(1, TTBFileName); no need, already has required name
20717 // now create the internal timetable from the .tmp file
20718  bool GiveMessagesFalse = false;
20719  bool CheckLocationsExistInRailwayTrue = true;
20720  if(TrainController->TimetableIntegrityCheck(1, TempTTFileName.c_str(), GiveMessagesFalse, CheckLocationsExistInRailwayTrue))
20721  {
20722  std::ifstream TTBLFile(TempTTFileName.c_str(), std::ios_base::binary);
20723  if(TTBLFile.is_open())
20724  {
20725  bool SessionFileTrue = true;
20726  if(!(BuildTrainDataVectorForLoadFile(1, TTBLFile, GiveMessagesFalse, CheckLocationsExistInRailwayTrue, SessionFileTrue)))
20727  {
20728  TTBLFile.close();
20729  DeleteFile(TempTTFileName);
20730  Utilities->CallLogPop(1224);
20731  return(false);
20732  }
20733  }
20734  else
20735  {
20736  DeleteFile(TempTTFileName);
20737  Utilities->CallLogPop(1225);
20738  return(false);
20739  }
20740  } // if(FileIntegrityCheck(TTBFileName.c_str()))
20741  else
20742  {
20743  DeleteFile(TempTTFileName);
20744  Utilities->CallLogPop(1226);
20745  return(false);
20746  }
20747 // DeleteFile(TempTTFileName); no, need to save it for later session saves
20748 
20749  // now need to load the TrainOperatingData so can be loaded back into the timetable
20750  int NumberOfTrainEntries = Utilities->LoadFileInt(SessionFile);
20751  if(NumberOfTrainEntries != (int)(TrainController->TrainDataVector.size()))
20752  {
20753  Utilities->CallLogPop(1811);
20754  return(false);
20755  }
20756  for(int x = 0; x < NumberOfTrainEntries; x++)
20757  {
20758  int NumberOfTrains = Utilities->LoadFileInt(SessionFile);
20759  if(NumberOfTrains != (int)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size()))
20760  {
20761  Utilities->CallLogPop(1812);
20762  return(false);
20763  }
20764  for(int y = 0; y < NumberOfTrains; y++)
20765  {
20766  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID = Utilities->LoadFileInt(SessionFile);
20767  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported = (TActionEventType)(Utilities->LoadFileInt(SessionFile));
20768  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry = (TRunningEntry)(Utilities->LoadFileInt(SessionFile));
20769  }
20770  }
20771  Utilities->CallLogPop(1227);
20772  return(true);
20773  }
20774  else
20775  {
20776  Utilities->CallLogPop(1228);
20777  return(false);
20778  }
20779 }
20780 
20781 // ---------------------------------------------------------------------------
20782 
20783 bool TInterface::CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
20784 // the .ttb section is delimited by '\0' followed by "***End***" & has been saved in binary mode, i.e. no '\0'
20785 // string delimiters between entries, this check function just checks the (non-zero terminated) string entries in the file without
20786 // trying to build a timetable - that's done during load
20787 {
20788  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTimetableFromSessionFile");
20789  AnsiString OutString;
20790 
20791  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
20792  {
20793  Utilities->CallLogPop(1229);
20794  return(false);
20795  }
20796  while(OutString != "***End***")
20797  {
20798  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
20799  {
20800  Utilities->CallLogPop(1230);
20801  return(false);
20802  }
20803  }
20804 // now need to check the TrainOperatingData, which was saved in text mode
20805  if(SessionFile.fail())
20806  {
20807  Utilities->CallLogPop(1231);
20808  return(false);
20809  }
20810  int NumberOfTrainEntries;
20811 
20812  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrainEntries))
20813  {
20814  Utilities->CallLogPop(1232);
20815  return(false);
20816  }
20817  for(int x = 0; x < NumberOfTrainEntries; x++)
20818  {
20819  int NumberOfTrains;
20820  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrains))
20821  {
20822  Utilities->CallLogPop(1233);
20823  return(false);
20824  }
20825  for(int y = 0; y < NumberOfTrains; y++)
20826  {
20827  if(!Utilities->CheckFileInt(SessionFile, -1, 1000000)) // TrainID
20828  {
20829  Utilities->CallLogPop(1234);
20830  return(false);
20831  }
20832  if(!Utilities->CheckFileInt(SessionFile, 0, 32)) // EventReported //increased to 32 at v2.11.1 due to Xeon error report 07/01/22 as there are 33
20833  //event reports now (increased at v2.9.1)
20834  {
20835  Utilities->CallLogPop(1235);
20836  return(false);
20837  }
20838  if(!Utilities->CheckFileInt(SessionFile, 0, 2)) // RunningEntry
20839  {
20840  Utilities->CallLogPop(1236);
20841  return(false);
20842  }
20843  }
20844  }
20845  Utilities->CallLogPop(1237);
20846  return(true);
20847 }
20848 
20849 // ---------------------------------------------------------------------------
20850 
20851 bool TInterface::BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
20852 {
20853  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForLoadFile," + AnsiString((short)GiveMessages));
20854  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
20855  bool EndOfFile = false;
20856  int Count = 0;
20857  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
20858 
20859  while(!EndOfFile)
20860  {
20861  TTBLFile.getline(TrainTimetableString, 10000, '\0');
20862  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
20863  {
20864  // may still have eof even if read a line (no CRLF at end), and
20865  // if so need to process it
20866  EndOfFile = true;
20867  break;
20868  }
20869  AnsiString OneLine(TrainTimetableString);
20870  bool FinalCallTrue = true;
20871  while((Count == 0) && !TrainController->ProcessOneTimetableLine(3, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
20872  CheckLocationsExistInRailway)) // get rid of lines before the start time
20873  {
20874  TTBLFile.getline(TrainTimetableString, 10000, '\0');
20875  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
20876  {
20877  TTBLFile.close();
20878  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
20879  }
20880  OneLine = AnsiString(TrainTimetableString);
20881  }
20882  // here when have accepted the start time
20883  if(Count == 0)
20884  {
20885  Count++; // increment past the start time
20886  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
20887  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
20888  {
20889  EndOfFile = true;
20890  OneLine = "";
20891  }
20892  else
20893  {
20894  OneLine = AnsiString(TrainTimetableString);
20895  }
20896  }
20897  if(!TrainController->ProcessOneTimetableLine(4, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
20898  {
20899  TTBLFile.close();
20900  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
20901  }
20902  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
20903  {
20904  TTBLFile.close();
20905  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
20906  }
20907  Count++;
20908  }
20909  TTBLFile.close();
20910  delete[]TrainTimetableString;
20911  bool TwoLocationFlag; //not used in LoadFile
20912 // here when first pass actions completed successfully
20913  if(!TrainController->SecondPassActions(0, GiveMessages, TwoLocationFlag)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
20914  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
20915  // messages given in function if errors & vector cleared
20916  {
20917  if(GiveMessages)
20918  {
20919  ShowMessage("Timetable secondary integrity check failed - unable to load");
20920  }
20921  Utilities->CallLogPop(1238);
20922  return(false);
20923  }
20924  else
20925  {
20926 // TimetableLoaded = true;
20927  if(!SessionFile) // new timetable being loaded so need new TimetableTitle, if SessionFile true then already have it from LoadInterface
20928  {
20929  for(int x = TimetableDialog->FileName.Length(); x > 0; x--)
20930  {
20931  if(TimetableDialog->FileName[x] == '\\')
20932  {
20933  TimetableTitle = TimetableDialog->FileName.SubString(x + 1, TimetableDialog->FileName.Length() - x - 4);
20934  SetCaption(4);
20935  break;
20936  }
20937  }
20938  }
20939 // if(GiveMessages) //only set BaseMode if have manually loaded a timetable changed for the below in v2.4.0
20940  if(!SessionFile) // only set BaseMode if have manually loaded a timetable, i.e SessionFile is false
20941  {
20942  Level1Mode = BaseMode;
20943  SetLevel1Mode(28);
20944  }
20945  }
20946  Utilities->CallLogPop(1239);
20947  return(true);
20948 }
20949 
20950 // ---------------------------------------------------------------------------
20951 
20952 bool TInterface::BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
20953 {
20954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForValidateFile," + AnsiString((short)GiveMessages));
20955  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
20956  bool EndOfFile = false;
20957  int Count = 0;
20958  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
20959 
20960  while(!EndOfFile)
20961  {
20962  TTBLFile.getline(TrainTimetableString, 10000, '\0');
20963  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
20964  {
20965  // may still have eof even if read a line (no CRLF at end), and
20966  // if so need to process it
20967  EndOfFile = true;
20968  break;
20969  }
20970  AnsiString OneLine(TrainTimetableString);
20971  bool FinalCallTrue = true;
20972  while((Count == 0) && !TrainController->ProcessOneTimetableLine(0, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
20973  CheckLocationsExistInRailway)) // get rid of lines before the start time
20974  {
20975  TTBLFile.getline(TrainTimetableString, 10000, '\0');
20976  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
20977  {
20978  TTBLFile.close();
20979  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
20980  }
20981  OneLine = AnsiString(TrainTimetableString);
20982  }
20983  // here when have accepted the start time
20984  if(Count == 0)
20985  {
20986  Count++; // increment past the start time
20987  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
20988  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
20989  {
20990  EndOfFile = true;
20991  OneLine = "";
20992  }
20993  else
20994  {
20995  OneLine = AnsiString(TrainTimetableString);
20996  }
20997  }
20998  if(!TrainController->ProcessOneTimetableLine(1, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
20999  {
21000  TTBLFile.close();
21001  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
21002  }
21003  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
21004  {
21005  TTBLFile.close();
21006  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
21007  }
21008  Count++;
21009  }
21010  TTBLFile.close();
21011  delete[]TrainTimetableString;
21012  bool TwoLocationFlag;
21013 // here when first pass actions completed successfully
21014  if(!TrainController->SecondPassActions(1, GiveMessages, TwoLocationFlag)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
21015  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
21016  // messages given in function if errors & vector cleared
21017  {
21018 // if(GiveMessages) ShowMessage("Timetable secondary integrity check failed");
21019 // above dropped in v2.4.0 as all called functions give own messages
21020  Utilities->CallLogPop(1665);
21021  return(false);
21022  }
21023  else if(TwoLocationFlag) //i.e returns true but have services with two or more locations without a cdt between //added at v2.9.1
21024  {
21025  AnsiString AllServices = "", Suffix = "";
21026  int Count = 1;
21028  {
21029  TwoLocationNamePanel->Top = TimetableEditPanel->Top + ((TimetableEditPanel->Height - TwoLocationNamePanel->Height) / 2);
21030  TwoLocationNamePanel->Left = TimetableEditPanel->Left + ((TimetableEditPanel->Width - TwoLocationNamePanel->Width) / 2);
21031  for(TTrainController::TServiceCallingLocsList::iterator TLLIt = TrainController->TwoLocationList.begin(); TLLIt != TrainController->TwoLocationList.end(); TLLIt++)
21032  {
21033  if(Count <= 5)
21034  {
21035  AllServices = AllServices + *TLLIt + ", ";
21036  }
21037  Count++;
21038  }
21039  if(Count > 6) //if exactly 5 entered then Count will be 6, Count always 1 more than entered
21040  {
21041  Suffix = "(more than 5, first 5 are) ";
21042  }
21043  if(Count > 2) //more than 1
21044  {
21045  TwoLocationNameLabel->Caption = "The following services have two or more locations with the same name without a change of\n"
21046  "direction between them. If this isn't intended then please correct them.\n\n"
21047  "Before ticking the check box please be sure that all services are correct.\n\n"
21048  "Services: " + Suffix + " " + AllServices;
21049  }
21050  else
21051  {
21052  TwoLocationNameLabel->Caption = "The following service has two or more locations with the same name without a change of\n"
21053  "direction between them. If this isn't intended then please correct it.\n\n"
21054  "Service: " + AllServices;
21055  }
21056  TwoLocationNamePanel->Visible = true;
21057  TwoLocationNamePanel->BringToFront();
21058  ShowHideTTButton->Enabled = false;
21059  ExitTTModeButton->Enabled = false;
21060  TimetableEditPanel->Enabled = false;
21061  }
21062  }
21063  Utilities->CallLogPop(1666);
21064  return(true);
21065 }
21066 
21067 // ---------------------------------------------------------------------------
21068 
21069 bool TInterface::SessionFileIntegrityCheck(int Caller, AnsiString FileName)
21070 /* Here need to check as far as timetable, then go back and load the track, because the timetable compilation check
21071 relies on the track vector and map being in place. Won't affect the later load because the vector and map are cleared
21072 before loading.
21073 
21074 Although this appears cumbersome, I initially used tellg() & seekg() to reposition the file pointer without having to do
21075 all this backtracking. However after many problems I eventually found that tellg() sometimes returns false values,
21076 which cause problems when reloaded using seekg(). This must be a compiler problem, though I could find no mention of it
21077 in the CBuilder4 issues list or on the web. The full write-up is at the end of this unit.
21078 
21079 Also, with hindsight, I wish I had just saved and reloaded the timetable vectors rather than the text of the timetable. That
21080 would probably have been easier. To change it now though would cause compatibility problems with sessions created by earlier versions.
21081 */
21082 {
21083  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SessionFileIntegrityCheck," + FileName);
21084  std::ifstream InFile(FileName.c_str());
21085 // first pass as far as timetable
21086  int NumberOfActiveElements;
21087  bool GraphicsFollow = false;
21088 
21089  if(InFile.is_open())
21090  {
21092  // expected to be "***Interface***" for original version or "Version + : ***Interface***" for later releases + ExcessLCDownMins added as float at v2.3.0
21093  {
21094  InFile.close();
21095  Utilities->CallLogPop(1240);
21096  return(false);
21097  }
21098  if(!CheckInterface(0, InFile))
21099  {
21100  InFile.close();
21101  Utilities->CallLogPop(1241);
21102  return(false);
21103  }
21104  // check track elements
21105  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
21106  {
21107  InFile.close();
21108  Utilities->CallLogPop(1242);
21109  return(false);
21110  }
21111  if(!Track->CheckTrackElementsInFile(2, NumberOfActiveElements, GraphicsFollow, InFile))
21112  {
21113  InFile.close();
21114  Utilities->CallLogPop(1243);
21115  return(false);
21116  }
21117  if(InFile.fail())
21118  {
21119  InFile.close();
21120  Utilities->CallLogPop(1244);
21121  return(false);
21122  }
21123  // check text elements
21124  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
21125  {
21126  InFile.close();
21127  Utilities->CallLogPop(1245);
21128  return(false);
21129  }
21130  if(!TextHandler->CheckTextElementsInFile(1, InFile))
21131  {
21132  InFile.close();
21133  Utilities->CallLogPop(1246);
21134  return(false);
21135  }
21136  if(InFile.fail())
21137  {
21138  InFile.close();
21139  Utilities->CallLogPop(1247);
21140  return(false);
21141  }
21142  // check PrefDir elements
21143  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
21144  {
21145  InFile.close();
21146  Utilities->CallLogPop(1248);
21147  return(false);
21148  }
21149  if(!EveryPrefDir->CheckOnePrefDir(1, NumberOfActiveElements, InFile))
21150  {
21151  InFile.close();
21152  Utilities->CallLogPop(1249);
21153  return(false);
21154  }
21155  if(InFile.fail())
21156  {
21157  InFile.close();
21158  Utilities->CallLogPop(1250);
21159  return(false);
21160  }
21161  // check graphics
21162  if(GraphicsFollow)
21163  {
21164  if(!Track->CheckUserGraphics(1, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
21165  {
21166  InFile.close();
21167  Utilities->CallLogPop(2187);
21168  return(false);
21169  }
21170  if(InFile.fail())
21171  {
21172  InFile.close();
21173  Utilities->CallLogPop(2188);
21174  return(false);
21175  }
21176  }
21177  // check routes
21178  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
21179  {
21180  InFile.close();
21181  Utilities->CallLogPop(1251);
21182  return(false);
21183  }
21184  if(!AllRoutes->CheckRoutes(0, NumberOfActiveElements, InFile))
21185  {
21186  InFile.close();
21187  Utilities->CallLogPop(1252);
21188  return(false);
21189  }
21190  if(InFile.fail())
21191  {
21192  InFile.close();
21193  Utilities->CallLogPop(1253);
21194  return(false);
21195  }
21196  // check LockedRoutes
21197  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
21198  {
21199  InFile.close();
21200  Utilities->CallLogPop(1254);
21201  return(false);
21202  }
21203  if(!TrainController->CheckSessionLockedRoutes(0, InFile))
21204  {
21205  InFile.close();
21206  Utilities->CallLogPop(1255);
21207  return(false);
21208  }
21209  if(InFile.fail())
21210  {
21211  InFile.close();
21212  Utilities->CallLogPop(1256);
21213  return(false);
21214  }
21215  // check ContinuationAutoSigs
21216  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
21217  {
21218  InFile.close();
21219  Utilities->CallLogPop(1257);
21220  return(false);
21221  }
21223  {
21224  InFile.close();
21225  Utilities->CallLogPop(1258);
21226  return(false);
21227  }
21228  if(InFile.fail())
21229  {
21230  InFile.close();
21231  Utilities->CallLogPop(1259);
21232  return(false);
21233  }
21234  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
21235  AnsiString TempString = Utilities->LoadFileString(InFile);
21236  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
21237  {
21238  InFile.close();
21239  Utilities->CallLogPop(1964);
21240  return(false);
21241  }
21242  if(TempString == "***BarriersDownVector***")
21243  {
21244  if(!Track->CheckActiveLCVector(0, InFile))
21245  {
21246  InFile.close();
21247  Utilities->CallLogPop(1965);
21248  return(false);
21249  }
21250  if(InFile.fail())
21251  {
21252  InFile.close();
21253  Utilities->CallLogPop(1966);
21254  return(false);
21255  }
21256  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
21257  {
21258  InFile.close();
21259  Utilities->CallLogPop(1260);
21260  return(false);
21261  }
21262  }
21263  // check timetable (marker string already checked immediately above)
21264  if(!CheckTimetableFromSessionFile(0, InFile))
21265  {
21266  InFile.close();
21267  Utilities->CallLogPop(1261);
21268  return(false);
21269  }
21270  if(InFile.fail())
21271  {
21272  InFile.close();
21273  Utilities->CallLogPop(1262);
21274  return(false);
21275  }
21276  }
21277  else
21278  {
21279  InFile.close();
21280 // ShowMessage("Session file failed to open, reason not known, unable to load session."); message given in calling function if returns false
21281  Utilities->CallLogPop(1263);
21282  return(false);
21283  }
21284 // now ready for the 2nd pass for timetable loading and checking
21285  InFile.close();
21286  InFile.open(FileName.c_str());
21287  if(InFile.is_open())
21288  {
21290  {
21291  InFile.close();
21292  Utilities->CallLogPop(1264);
21293  return(false);
21294  }
21295  if(!CheckInterface(1, InFile))
21296  {
21297  InFile.close();
21298  Utilities->CallLogPop(1265);
21299  return(false);
21300  }
21301  // load track elements
21302  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
21303  {
21304  InFile.close();
21305  Utilities->CallLogPop(1266);
21306  return(false);
21307  }
21308  bool GraphicsFollow = false;
21309  Track->LoadTrack(2, InFile, GraphicsFollow); // load the track this time
21310  if(InFile.fail())
21311  {
21312  InFile.close();
21313  Utilities->CallLogPop(1267);
21314  return(false);
21315  }
21316  // check text elements
21317  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
21318  {
21319  InFile.close();
21320  Utilities->CallLogPop(1268);
21321  return(false);
21322  }
21323  if(!TextHandler->CheckTextElementsInFile(2, InFile))
21324  {
21325  InFile.close();
21326  Utilities->CallLogPop(1269);
21327  return(false);
21328  }
21329  if(InFile.fail())
21330  {
21331  InFile.close();
21332  Utilities->CallLogPop(1270);
21333  return(false);
21334  }
21335  // check PrefDir elements
21336  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
21337  {
21338  InFile.close();
21339  Utilities->CallLogPop(1271);
21340  return(false);
21341  }
21342  if(!EveryPrefDir->CheckOnePrefDir(2, NumberOfActiveElements, InFile))
21343  {
21344  InFile.close();
21345  Utilities->CallLogPop(1272);
21346  return(false);
21347  }
21348  if(InFile.fail())
21349  {
21350  InFile.close();
21351  Utilities->CallLogPop(1273);
21352  return(false);
21353  }
21354  // check graphics
21355  if(GraphicsFollow)
21356  {
21357  if(!Track->CheckUserGraphics(2, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
21358  {
21359  InFile.close();
21360  Utilities->CallLogPop(2189);
21361  return(false);
21362  }
21363  if(InFile.fail())
21364  {
21365  InFile.close();
21366  Utilities->CallLogPop(2190);
21367  return(false);
21368  }
21369  }
21370  // check routes
21371  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
21372  {
21373  InFile.close();
21374  Utilities->CallLogPop(1274);
21375  return(false);
21376  }
21377  if(!AllRoutes->CheckRoutes(1, NumberOfActiveElements, InFile))
21378  {
21379  InFile.close();
21380  Utilities->CallLogPop(1275);
21381  return(false);
21382  }
21383  if(InFile.fail())
21384  {
21385  InFile.close();
21386  Utilities->CallLogPop(1276);
21387  return(false);
21388  }
21389  // check LockedRoutes
21390  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
21391  {
21392  InFile.close();
21393  Utilities->CallLogPop(1277);
21394  return(false);
21395  }
21396  if(!TrainController->CheckSessionLockedRoutes(1, InFile))
21397  {
21398  InFile.close();
21399  Utilities->CallLogPop(1278);
21400  return(false);
21401  }
21402  if(InFile.fail())
21403  {
21404  InFile.close();
21405  Utilities->CallLogPop(1279);
21406  return(false);
21407  }
21408  // check ContinuationAutoSigs
21409  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
21410  {
21411  InFile.close();
21412  Utilities->CallLogPop(1280);
21413  return(false);
21414  }
21416  {
21417  InFile.close();
21418  Utilities->CallLogPop(1281);
21419  return(false);
21420  }
21421  if(InFile.fail())
21422  {
21423  InFile.close();
21424  Utilities->CallLogPop(1282);
21425  return(false);
21426  }
21427  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
21428  AnsiString TempString = Utilities->LoadFileString(InFile);
21429  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
21430  {
21431  InFile.close();
21432  Utilities->CallLogPop(1967);
21433  return(false);
21434  }
21435  if(TempString == "***BarriersDownVector***")
21436  {
21437  if(!Track->CheckActiveLCVector(0, InFile))
21438  {
21439  InFile.close();
21440  Utilities->CallLogPop(1968);
21441  return(false);
21442  }
21443  if(InFile.fail())
21444  {
21445  InFile.close();
21446  Utilities->CallLogPop(1969);
21447  return(false);
21448  }
21449  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
21450  {
21451  InFile.close();
21452  Utilities->CallLogPop(1283);
21453  return(false);
21454  }
21455  }
21456  // check timetable (marker string already checked)
21457  if(!LoadTimetableFromSessionFile(1, InFile))
21458  {
21459  InFile.close();
21460  Utilities->CallLogPop(1284);
21461  return(false);
21462  }
21463  if(InFile.fail())
21464  {
21465  InFile.close();
21466  Utilities->CallLogPop(1285);
21467  return(false);
21468  }
21469  // check timetable clock
21470  if(!Utilities->CheckAndCompareFileString(InFile, "***TimetableClock***"))
21471  {
21472  InFile.close();
21473  Utilities->CallLogPop(1286);
21474  return(false);
21475  }
21476  if(!Utilities->CheckFileDouble(InFile))
21477  {
21478  InFile.close();
21479  Utilities->CallLogPop(1287);
21480  return(false);
21481  }
21482  // check trains
21483  if(!Utilities->CheckAndCompareFileString(InFile, "***Trains***"))
21484  {
21485  InFile.close();
21486  Utilities->CallLogPop(1288);
21487  return(false);
21488  }
21489  if(!TrainController->CheckSessionTrains(0, InFile))
21490  {
21491  InFile.close();
21492  Utilities->CallLogPop(1289);
21493  return(false);
21494  }
21495  if(InFile.fail())
21496  {
21497  InFile.close();
21498  Utilities->CallLogPop(1290);
21499  return(false);
21500  }
21501  if(!Utilities->CheckAndCompareFileString(InFile, "***Performance file***"))
21502  {
21503  InFile.close();
21504  Utilities->CallLogPop(1291);
21505  return(false);
21506  }
21507  if(!CheckPerformanceFile(0, InFile))
21508  {
21509  InFile.close();
21510  Utilities->CallLogPop(1292);
21511  return(false);
21512  }
21513  char TempChar;
21514  InFile.get(TempChar);
21515  while(!InFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
21516  {
21517  InFile.get(TempChar);
21518  }
21519  if(!InFile.eof()) // additional checks needed
21520  {
21521  if(!Utilities->CheckFileString(InFile))
21522  {
21523  InFile.close();
21524  Utilities->CallLogPop(2198);
21525  return(false);
21526  }
21527  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // TrainController->AvHoursIntValue
21528  {
21529  InFile.close();
21530  Utilities->CallLogPop(2199);
21531  return(false);
21532  }
21533  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // number of train failures
21534  {
21535  InFile.close();
21536  Utilities->CallLogPop(2200);
21537  return(false);
21538  }
21539  // now check any failed trains along with their OriginalPowerAtRail values
21540  Utilities->CheckFileString(InFile); // discard "***Failed Trains***"
21541  int IDVal;
21542  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal)) // train ID or -1 for no more failed trains,
21543  {
21544  InFile.close();
21545  Utilities->CallLogPop(2201);
21546  return(false);
21547  }
21548  double PowerDouble;
21549  while(IDVal != -1)
21550  {
21551  Utilities->CheckFileDouble(InFile); // original power
21552  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal))
21553  {
21554  InFile.close();
21555  Utilities->CallLogPop(2202);
21556  return(false);
21557  }
21558  }
21559  }
21560  InFile.close();
21561  }
21562  else
21563  {
21564  InFile.close();
21565  Utilities->CallLogPop(1293);
21566  return(false);
21567  }
21568  Utilities->CallLogPop(1294);
21569  return(true);
21570 }
21571 
21572 // ---------------------------------------------------------------------------
21573 
21574 void TInterface::LoadPerformanceFile(int Caller, std::ifstream &InFile)
21575 // Note that the file integrity has already been checked using CheckPerformanceFile
21576 {
21577  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPerformanceFile");
21578  AnsiString TempString = "", Line1 = "", Line2 = "", Line3 = "", Line4 = "", Line5 = "";
21579  char *Buffer = new char[1000];
21580  char TempChar;
21581 
21582  InFile.get(TempChar); // '\n'
21583  InFile.getline(Buffer, 1000);
21584  TempString = AnsiString(Buffer);
21585  if(TempString == "***End of performance file***") //added at v2.10.0
21586  {
21587  Display->PerformanceLog(17, "Performance Log\nRailway: " + RailwayTitle + "\nTimetable: " + TimetableTitle + "\nStart Time: " +
21588  TrainController->TimetableStartTime.FormatString("hh:nn"));
21589  }
21590  else
21591  {
21592  while(TempString != "***End of performance file***")
21593  {
21594  PerformanceLogBox->Lines->Add(TempString);
21595  Utilities->PerformanceFile << TempString.c_str() << '\n';
21596  Utilities->PerformanceFile.flush(); //added at v2.13.0
21597  InFile.getline(Buffer, 1000);
21598  TempString = AnsiString(Buffer);
21599  }
21600  }
21601  delete[] Buffer;
21602  Utilities->CallLogPop(1295);
21603 }
21604 
21605 // ---------------------------------------------------------------------------
21606 
21607 bool TInterface::CheckPerformanceFile(int Caller, std::ifstream &InFile)
21608 {
21609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPerformanceFile");
21610  AnsiString TempString = "";
21611  char TempChar;
21612 
21613  InFile.get(TempChar);
21614  if(TempChar != '\n')
21615  {
21616  Utilities->CallLogPop(1296);
21617  return(false);
21618  }
21619  if(!Utilities->CheckAndReadFileString(InFile, TempString))
21620  {
21621  Utilities->CallLogPop(1297);
21622  return(false);
21623  }
21624  while(TempString != "***End of performance file***")
21625  {
21626  if(!Utilities->CheckAndReadFileString(InFile, TempString))
21627  {
21628  Utilities->CallLogPop(1298);
21629  return(false);
21630  }
21631  }
21632  Utilities->CallLogPop(1299);
21633  return(true);
21634 }
21635 
21636 // ---------------------------------------------------------------------------
21637 
21638 void TInterface::SavePerformanceFile(int Caller, std::ofstream &OutFile)
21639 {
21640  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePerformanceFile");
21641  AnsiString Text = PerformanceLogBox->Text;
21642 
21643  while(Text != "")
21644  {
21645  AnsiString OneLine = Text.SubString(1, Text.Pos('\x0D'));
21646  while((OneLine.Length() > 0) && OneLine[OneLine.Length()] < ' ')
21647  {
21648  OneLine.SetLength(OneLine.Length() - 1); // get rid of trailing control characters
21649  }
21650  Text = Text.SubString(Text.Pos('\x0D'), Text.Length());
21651  while((Text.Length() > 0) && Text[1] < ' ')
21652  {
21653  Text = Text.SubString(2, (Text.Length() - 1)); // get rid of leading control characters
21654  }
21655  OutFile << OneLine.c_str() << '\n';
21656  }
21657  Utilities->CallLogPop(1300);
21658 }
21659 
21660 // ---------------------------------------------------------------------------
21661 
21663 {
21664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteButtonsInfoCaptionAndRouteNotStarted");
21665  if(EveryPrefDir->PrefDirSize() > 0)
21666  {
21667  if(AutoSigsFlag)
21668  {
21669  AutoSigsButton->Enabled = false;
21670  SigPrefConsecButton->Enabled = true;
21671  SigPrefNonConsecButton->Enabled = true;
21672  UnrestrictedButton->Enabled = true;
21673  InfoPanel->Visible = true;
21674  if(Level2OperMode == PreStart)
21675  {
21676  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
21677  }
21678  else
21679  {
21680  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
21681  }
21682  InfoCaptionStore = InfoPanel->Caption;
21683  }
21684  else if(PreferredRoute & ConsecSignalsRoute) // added at v2.7.0, was just ConsecSignalsRoute
21685  {
21686  AutoSigsButton->Enabled = true;
21687  SigPrefConsecButton->Enabled = false;
21688  SigPrefNonConsecButton->Enabled = true;
21689  UnrestrictedButton->Enabled = true;
21690  InfoPanel->Visible = true;
21691  if(Level2OperMode == PreStart)
21692  {
21693  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
21694  }
21695  else
21696  {
21697  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
21698  }
21699  InfoCaptionStore = InfoPanel->Caption;
21700  }
21701  else if(PreferredRoute&!ConsecSignalsRoute) // added at v2.7.0
21702  {
21703  AutoSigsButton->Enabled = true;
21704  SigPrefConsecButton->Enabled = true;
21705  SigPrefNonConsecButton->Enabled = false;
21706  UnrestrictedButton->Enabled = true;
21707  InfoPanel->Visible = true;
21708  if(Level2OperMode == PreStart)
21709  {
21710  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
21711  }
21712  else
21713  {
21714  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
21715  }
21716  InfoCaptionStore = InfoPanel->Caption;
21717  }
21718  else
21719  {
21720  AutoSigsButton->Enabled = true;
21721  SigPrefConsecButton->Enabled = true;
21722  SigPrefNonConsecButton->Enabled = true;
21723  UnrestrictedButton->Enabled = false;
21724  InfoPanel->Visible = true;
21725  if(Level2OperMode == PreStart)
21726  {
21727  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
21728  }
21729  else
21730  {
21731  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
21732  }
21733  InfoCaptionStore = InfoPanel->Caption;
21734  }
21735  }
21736  else
21737  {
21738  AutoSigsButton->Enabled = false;
21739  SigPrefConsecButton->Enabled = false;
21740  SigPrefNonConsecButton->Enabled = false;
21741  UnrestrictedButton->Enabled = false;
21742  InfoPanel->Visible = true;
21743  if(Level2OperMode == PreStart)
21744  {
21745  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
21746  }
21747  else
21748  {
21749  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
21750  }
21751  InfoCaptionStore = InfoPanel->Caption;
21752  }
21754  {
21755  RouteCancelButton->Enabled = true;
21756  }
21757  else
21758  {
21759  RouteCancelButton->Enabled = false;
21760  }
21762  AutoRouteStartMarker->PlotOriginal(37, Display); // so start marker will replot if had selected start before pause & zoom
21765  Utilities->CallLogPop(1301);
21766 }
21767 
21768 // ---------------------------------------------------------------------------
21769 
21771 {
21772  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetPausedOrZoomedInfoCaption");
21773  if(Display->ZoomOutFlag)
21774  {
21775  InfoPanel->Visible = true;
21776  InfoPanel->Caption = "Left click screen to zoom in at that position";
21777  }
21778  else if(Level2OperMode == Paused)
21779  {
21780  InfoPanel->Visible = true;
21781  InfoPanel->Caption = "PAUSED: Railway state changes disabled";
21782  }
21783 // otherwise do nothing
21784  Utilities->CallLogPop(1302);
21785 }
21786 
21787 // ---------------------------------------------------------------------------
21788 
21790 {
21791  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisableRouteButtons");
21792  RouteCancelButton->Enabled = false;
21793  AutoSigsButton->Enabled = false;
21794  SigPrefConsecButton->Enabled = false;
21795  SigPrefNonConsecButton->Enabled = false;
21796  UnrestrictedButton->Enabled = false;
21797  Utilities->CallLogPop(1303);
21798 }
21799 
21800 // ---------------------------------------------------------------------------
21801 
21803 // no need for call logging as already failed
21804 {
21805 /*
21806  In order to reload as a session file:
21807 
21808  NB: Don't change it to a .txt file, as the '\0' characters [shown as a small square in wordpad] will be changed to spaces if it is subsequently saved
21809  strip out:-
21810 
21811  [since adding user graphics after prefdirs need to take this into account]
21812 
21813  up to but excluding ***Interface***
21814  from & including ***ConstructPrefDir PrefDirVector***
21815  to but excluding ***PrefDirs***
21816  if there is a single line ***UserGraphics*** delete it (won't be present if no graphics)
21817  from & including ***ConstructRoute PrefDirVector***
21818  to but excluding ***Routes***
21819  from & including ***ChangingLCVector*** to but excluding ***Timetable*** [if have ***No timetable loaded*** then can't use as a session file]
21820  from & including ***No editing timetable*** or ***Editing timetable - [title]***
21821  to but excluding ***TimetableClock***
21822  from but excluding End of file at v2.11.0
21823  to end of file
21824 
21825  and save as a .ssn file.
21826 
21827  In order to load as a railway file: Note if error involves cut/copy etc with prefdirs then need to drop the check of CheckCount
21828 
21829  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
21830 
21831  note or copy the version information at the top of the file
21832  copy the two numbers on rows 7 & 8 below ***Interface*** (i.e ***Interface*** = row 0) on their own lines immediately after the ***Track*** line (these become DisplayOffsetH & V)
21833  strip out up to but excluding ***Track*** - this is needed to keep the \0 entry at end of ***Track*** [shown as a small square in wordpad]
21834  add the version number either before or instead of ***Track***, ensuring that the \0 is retained
21835  the next line after the two insertions should contain the number of active elements.
21836  strip out ***Text*** including the \0
21837  strip out from & including ***ConstructPrefDir PrefDirVector*** to & including ***PrefDirs*** (and the \0's)
21838  strip out ***UserGraphics*** including the \0 <--this is missing
21839  strip out from & including the number preceding ***ConstructRoute SearchVector*** to the end of the file
21840  the last entry should be '************NUL CR LF' (after all the pref dirs)
21841  rename as .dev or .rly file
21842 
21843  BUT - note that signals (and points, though they won't show) will be set as they were left. To reset to red, load a suitable timetable & select
21844  'Operate' then 'Exit operation'.
21845 */
21846 
21847 /*
21848  In order to extract a timetable:
21849 
21850  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
21851 
21852  set wordwrap to window on
21853  strip out all to and including ***Timetable*** or ***Editing timetable.... depending which is to be saved
21854  ensure any text before start time ends with /0, otherwise don't need the \0
21855  strip out all after the final /0 immediately before ***End*** or ***End of timetable***, but ensure leave the final /0
21856  save as a .ttb file
21857 */
21858 
21859  Screen->Cursor = TCursor(-11); // Hourglass;
21860  AnsiString ErrorFileStr = CurDir + "\\errorlog.err";
21861  std::ofstream ErrorFile(ErrorFileStr.c_str());
21862 
21863  if(!(ErrorFile.fail()))
21864  {
21865 // save mouse position relative to mainscreen
21866  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
21867  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
21868  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
21869  Utilities->SaveFileString(ErrorFile, MouseStr);
21870 // save call stack
21871  Utilities->SaveFileString(ErrorFile, "***Call stack***");
21872  for(unsigned int x = 0; x < Utilities->CallLog.size(); x++)
21873  {
21874  AnsiString Item = Utilities->CallLog.at(x);
21875  ErrorFile << Item.c_str() << '\n';
21876  }
21877 // save event log
21878  Utilities->SaveFileString(ErrorFile, "***Event log***");
21879  for(unsigned int x = 0; x < Utilities->EventLog.size(); x++)
21880  {
21881  AnsiString Item = Utilities->EventLog.at(x);
21882  ErrorFile << Item.c_str() << '\n';
21883  }
21884 // save interface
21885  Utilities->SaveFileString(ErrorFile, "***Interface***");
21886  SaveInterface(1, ErrorFile);
21887 // save track elements
21888  Utilities->SaveFileString(ErrorFile, "***Track***");
21889  if(Track->UserGraphicVector.empty())
21890  {
21891  Track->SaveTrack(2, ErrorFile, false); // false for no graphics (**Active elements** saved as marker)
21892  }
21893  else
21894  {
21895  Track->SaveTrack(12, ErrorFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
21896  }
21897 // save text elements
21898  Utilities->SaveFileString(ErrorFile, "***Text***");
21899  TextHandler->SaveText(3, ErrorFile);
21900 // save ConstructPrefDir PrefDirVector elements
21901  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir PrefDirVector***");
21902  ConstructPrefDir->SavePrefDirVector(7, ErrorFile);
21903 // save ConstructPrefDir SearchVector elements
21904  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir SearchVector***");
21905  ConstructPrefDir->SaveSearchVector(0, ErrorFile);
21906 // save EveryPrefDir elements
21907  Utilities->SaveFileString(ErrorFile, "***PrefDirs***");
21908  EveryPrefDir->SavePrefDirVector(3, ErrorFile);
21909  if(!Track->UserGraphicVector.empty())
21910  {
21911  // save user graphics
21912  Utilities->SaveFileString(ErrorFile, "***UserGraphics***");
21913  Track->SaveUserGraphics(3, ErrorFile);
21914  }
21915 // save ConstructRoute PrefDirVector
21916  Utilities->SaveFileString(ErrorFile, "***ConstructRoute PrefDirVector***");
21917  ConstructRoute->SavePrefDirVector(4, ErrorFile);
21918 // save ConstructRoute SearchVector
21919  Utilities->SaveFileString(ErrorFile, "***ConstructRoute SearchVector***");
21920  ConstructRoute->SaveSearchVector(1, ErrorFile);
21921 // save AllRoutes
21922  Utilities->SaveFileString(ErrorFile, "***Routes***");
21923  AllRoutes->SaveRoutes(1, ErrorFile);
21924 // save LockedRoutes
21925  Utilities->SaveFileString(ErrorFile, "***Locked routes***");
21927 // save ContinuationAutoSigEntries
21928  Utilities->SaveFileString(ErrorFile, "***ContinuationAutoSigEntries***");
21930 // save BarriersDownVector
21931  Utilities->SaveFileString(ErrorFile, "***BarriersDownVector***");
21932  Track->SaveSessionBarriersDownVector(1, ErrorFile);
21933 // save ChangingLCVector
21934  Utilities->SaveFileString(ErrorFile, "***ChangingLCVector***");
21935  Track->SaveChangingLCVector(0, ErrorFile);
21936 // save loaded timetable
21937  if(TimetableTitle == "")
21938  {
21939  Utilities->SaveFileString(ErrorFile, "***No timetable loaded***");
21940  }
21941  else
21942  {
21943  Utilities->SaveFileString(ErrorFile, "***Timetable***");
21944  if(!(SaveTimetableToSessionFile(1, ErrorFile, ErrorFileStr)))
21945  {
21946  Utilities->SaveFileString(ErrorFile, "***Loaded timetable failed to save***");
21947  }
21948  }
21949 // save editing timetable
21950  if(CreateEditTTTitle == "")
21951  {
21952  Utilities->SaveFileString(ErrorFile, "***No editing timetable***");
21953  }
21954  else
21955  {
21956  Utilities->SaveFileString(ErrorFile, "***Editing timetable - " + CreateEditTTTitle + "***");
21957  if(!(SaveTimetableToErrorFile(1, ErrorFile, ErrorFileStr, CreateEditTTFileName)))
21958  {
21959  Utilities->SaveFileString(ErrorFile, "***Editing timetable failed to save***");
21960  }
21961  }
21962 // save TimetableClock
21963  Utilities->SaveFileString(ErrorFile, "***TimetableClock***");
21964  Utilities->SaveFileDouble(ErrorFile, double(TrainController->TTClockTime));
21965 // save trains
21966  Utilities->SaveFileString(ErrorFile, "***Trains***");
21967  TrainController->SaveSessionTrains(1, ErrorFile);
21968 // save performance file
21969  Utilities->SaveFileString(ErrorFile, "***Performance file***");
21970  SavePerformanceFile(1, ErrorFile);
21971  Utilities->SaveFileString(ErrorFile, "***End of performance file***");
21972 // addition at v2.4.1 to save TrainController->AvHoursIntValue + any future additions
21973  Utilities->SaveFileString(ErrorFile, "***Additions after v2.3.1***");
21976  Utilities->SaveFileString(ErrorFile, "***Failed Trains***");
21977  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
21978  {
21980  {
21983  }
21984  }
21985  Utilities->SaveFileInt(ErrorFile, -1); // marker for end of failed trains
21986  Utilities->SaveFileString(ErrorFile, "End of file at v2.4.1");
21987 // end of v2.4.1 addition
21988 
21989 // added at v2.7.0 - extras saved later in session file (added at v2.9.2)
21991  Utilities->SaveFileString(ErrorFile, "End of file at v2.7.0");
21992 // end of v2.7.0 addition
21993 
21994 // added at v2.9.1
22000  Utilities->SaveFileString(ErrorFile, "End of v2.9.1 additions"); //changed from '2.9.0' at v2.9.2
22001 // end of v2.9.1 additions
22002 
22003 //added at v2.11.0
22004 //add SkippedTTEvents
22006 // add data for trains in process of skipping timetable events (i.e. those with events after a future departure)
22007  if(!TrainController->TrainVector.empty())
22008  {
22009  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
22010  {
22011  TTrain Train = TrainController->TrainVectorAt(83, x);
22012  if(Train.SkippedDeparture)
22013  {
22014  Utilities->SaveFileInt(ErrorFile, Train.TrainID);
22015  Utilities->SaveFileBool(ErrorFile, Train.SkippedDeparture);
22016  Utilities->SaveFileBool(ErrorFile, Train.ActionsSkippedFlag);
22017  Utilities->SaveFileInt(ErrorFile, Train.SkipPtrValue);
22018  Utilities->SaveFileInt(ErrorFile, Train.TrainSkippedEvents);
22019  }
22020  }
22021  }
22022  Utilities->SaveFileString(ErrorFile, "End of file at v2.11.0");
22023 //end of 2.11.0 additions
22024 
22025 //additions at v2.12.0 - become new service early & treat pass as departure
22026  if(!TrainController->TrainVector.empty())
22027  {
22028  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
22029  {
22030  TTrain Train = TrainController->TrainVectorAt(86, x);
22031  if(Train.TreatPassAsTimeLocDeparture) //this can only apply once for a single train (service repeats are separate trains)
22032  {
22033  Utilities->SaveFileInt(ErrorFile, Train.TrainID);
22034  }
22035  }
22036  }
22037  Utilities->SaveFileString(ErrorFile, "End of file at v2.12.0");
22038 //end of v2.12.0 additions
22039 
22040 
22041 //REMAINDER STAY AT END OF FILE
22042 // addition at v2.8.0 in case of clipboard errors <-- keep at end of file as not wanted in a reconstructed session file
22043  Utilities->SaveFileInt(ErrorFile, SelectBitmap->Height); // extras for new clipboard functions
22044  Utilities->SaveFileInt(ErrorFile, SelectBitmap->Width);
22045  Utilities->SaveFileInt(ErrorFile, SelectBitmapHLoc); // paste location
22046  Utilities->SaveFileInt(ErrorFile, SelectBitmapVLoc);
22047  Utilities->SaveFileInt(ErrorFile, SelectRect.left); // original selection location
22048  Utilities->SaveFileInt(ErrorFile, SelectRect.top);
22049  Utilities->SaveFileInt(ErrorFile, SelectRect.right);
22050  Utilities->SaveFileInt(ErrorFile, SelectRect.bottom);
22051  Utilities->SaveFileString(ErrorFile, "End of clipboard additions");
22052 // end of 2.8.0 addition
22053  ErrorFile.close();
22054  }
22055  else
22056  {
22057  TrainController->StopTTClockMessage(6, "Error file failed to open, error log won't be saved.");
22058  }
22059  Screen->Cursor = TCursor(-2); // Arrow
22060 }
22061 
22062 // ---------------------------------------------------------------------------
22063 
22064 void TInterface::SaveTempTimetableFile(int Caller, AnsiString InFileName)
22065 // the .ttb section is delimited by '\n' followed by "***End***"
22066 // first create a .ttb file in the working folder exactly like the original
22067 
22068 // Note: this type of file use failed when used to resave timetable.tmp from temp .ttb file, but changed that to avoid so many rapid
22069 // file actions in quick succession & been OK since then, but nevertheless keep the 10 retries before giving message to be on safe side
22070 {
22071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTempTimetableFile");
22072  if((TempTTFileName != "") && FileExists(TempTTFileName))
22073  {
22074  DeleteFile(TempTTFileName);
22075  }
22076  int TempTTFileNumber = 0;
22077 
22078  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
22079  {
22080  TempTTFileNumber++;
22081  }
22082  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
22083  int InHandle = FileOpen(InFileName, fmOpenRead);
22084  int Count = 0;
22085 
22086  while(InHandle < 0) // sometimes fails, have 10 retries before giving message
22087  {
22088  InHandle = FileOpen(InFileName, fmOpenRead);
22089  Count++;
22090  Delay(2, 50); // 50mSec delay between tries
22091  if(Count > 10)
22092  {
22093  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
22094  Utilities->CallLogPop(1400);
22095  return;
22096  }
22097  }
22098  int OutHandle = FileCreate(TempTTFileName);
22099 
22100  Count = 0;
22101  while(OutHandle < 0) // sometimes fails, have 10 retries before giving message
22102  {
22103  OutHandle = FileCreate(TempTTFileName);
22104  Count++;
22105  Delay(3, 50); // 50mSec delay between tries
22106  if(Count > 10)
22107  {
22108  ShowMessage("Failed to save temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
22109  FileClose(InHandle);
22110  Utilities->CallLogPop(1401);
22111  return;
22112  }
22113  }
22114  int CountIn, CountOut;
22115  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
22116 
22117  while(true)
22118  {
22119  CountIn = FileRead(InHandle, Buffer, 10000);
22120  CountOut = FileWrite(OutHandle, Buffer, CountIn);
22121  if(CountOut != CountIn)
22122  {
22123  ShowMessage("Error in writing to the temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
22124  delete[]Buffer;
22125  FileClose(InHandle);
22126  FileClose(OutHandle);
22127  Utilities->CallLogPop(1402);
22128  return;
22129  }
22130  if(CountIn < 10000)
22131  {
22132  break;
22133  }
22134  }
22135  delete[]Buffer;
22136  FileClose(InHandle);
22137  FileClose(OutHandle);
22138  Utilities->CallLogPop(1403);
22139 }
22140 
22141 // ---------------------------------------------------------------------------
22142 
22143 void TInterface::SetTrackLengths(int Caller, int Distance, int SpeedLimit) // Distance & SpeedLimit are -1 for no change to that parameter
22144 /*
22145  Rules: Platforms are fixed length elements of 100m and aren't changed - no, see note below. Variable length elements can't be less than 10m.
22146  above changed in v2.4.0 to be variable as other track, but if <50m or >200m a warning is given
22147 
22148  Enter with DistanceVector containing the PrefDir to be set, Distance containing the required sum of all element lengths,
22149  and SpeedLimit containing the speed limit. If either of these is -1 (can be -1 separately) then no change is to be made to it.
22150  Return for an empty DistanceVector. Deal first with a single element in the vector, giving a message if there is a platform there.
22151  Now set exit link position (XLinkPos) value for the first element in DistanceVector by checking which link connects to the second
22152  element in the vector, and give a warning message if fail to find it. Now have to make two passes through the vector, firstly to
22153  sum the fixed lengths, count the number of variable length elements and set the speed limit, and secondly to set the lengths.
22154  Firstly store the first XLinkPos so don't have to recalculate it for the second pass. On the first pass examine each element,
22155  incrementing the variable element count or summing the fixed length count as go along, and setting the speed limits providing
22156  SpeedLimit isn't -1. If Distance was -1 then still go through but don't count anything, just set the speed limits. Recalculate
22157  the next XLinkPos for each succeeding element.
22158  After the first pass return if Distance was -1 as in that case have now finished. Otherwise check if the distance to be set is less than
22159  the minimum possible within the rules, and if so give a message and return. Also give a warning message if there aren't any variable length
22160  elements. Now enter the second pass. In this the length of each variable element is set to int(RemainingDistance/RemainingVarElements) and
22161  fixed length elements are ignored. After each variable length element is set the RemainingDistance and RemainingVarElements are recalculated
22162  ready for the next setting. In this way there is never more than 1 difference between any two variable length elements and the total
22163  distance sums exactly to the value required. A check is made after every variable length element has been set to see whether RemainingDistance
22164  and RemainingVarElements are zero, and if they don't reach zero together (which they should after the last variable length element has
22165  been set), an error message is given.
22166 */
22167 
22168 {
22169  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLengths," + AnsiString(Distance) + "," + AnsiString(SpeedLimit));
22170  bool FoundFlag;
22171 
22172 // ResetDistanceElements(4);
22173  if(ConstructPrefDir->PrefDirSize() == 0)
22174  {
22175  Utilities->CallLogPop(608);
22176  return;
22177  }
22178 // must have PrefDir size of at least 2
22179 
22180 // first pass to count number of variable length elements, sum fixed lengths & set speed limit
22181 // for version in v2.4.0 have no fixed length elements but leave code as is as much as possible
22182  int VarElements = 0; // FixedLength = 0; drop this in v2.4.0
22183  bool NamedLocPresent = false;
22184 
22185  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
22186  {
22187  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(167, x);
22188  TTrackElement & TE = Track->TrackElementAt(34, Track->GetVectorPositionFromTrackMap(28, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
22189  if(!FoundFlag)
22190  {
22191  throw Exception("Error - failed to find track element at " + AnsiString(TE.HLoc) + " & " + AnsiString(TE.VLoc) + " in SetLengths");
22192  }
22193  if((Distance != -1) && (!Track->IsPlatformOrNamedNonStationLocationPresent(2, TE.HLoc, TE.VLoc)))
22194  {
22195  VarElements++;
22196  }
22197  else if((Distance != -1) && (Track->IsPlatformOrNamedNonStationLocationPresent(3, TE.HLoc, TE.VLoc)))
22198  {
22199  VarElements++; // added in v2.4.0 for no fixed elements
22200  NamedLocPresent = true;
22201 // FixedLength+= DefaultTrackLength; dropped in v2.4.0 for no fixed elements
22202  }
22203  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be points
22204  {
22205  if(SpeedLimit != -1)
22206  {
22207  TE.SpeedLimit01 = SpeedLimit;
22208  }
22209  }
22210  else
22211  {
22212  if(SpeedLimit != -1)
22213  {
22214  TE.SpeedLimit23 = SpeedLimit;
22215  }
22216  }
22217  }
22218  if(Distance == -1) // can't return before this as need to set speed limits
22219  {
22220  Utilities->CallLogPop(612);
22221  return;
22222  }
22223  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) < 50)) // these two additions are for in v2.4.0
22224  {
22225  if(!TooShortMessageSentFlag) //added at v2.9.1
22226  {
22227  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might be too unrealistic.\n\nThis message will not be shown again.");
22228  TooShortMessageSentFlag = true; //added at v2.9.1
22229  }
22230  }
22231  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) > 200))
22232  {
22233  if(!TooLongMessageSentFlag) //added at v2.9.1
22234  {
22235  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might be too unrealistic.\n\nThis message will not be shown again.");
22236  TooLongMessageSentFlag = true; //added at v2.9.1
22237  }
22238  }
22239  if((VarElements * 10) > Distance) // removed '+ FixedLength'
22240  {
22241  ShowMessage("Required distance is less than the minimum, will set each element to the minimum (10m)");
22242  Distance = (VarElements * 10); // removed '+ FixedLength'
22243  }
22244  if(VarElements == 0)
22245  {
22246 // ShowMessage("Unable to set distance as all elements are of fixed length"); as was
22247  ShowMessage("No elements selected"); // probably don't need this but include for safety
22248  Utilities->CallLogPop(613);
22249  return;
22250  }
22251 // second pass, set variable lengths
22252  int RemainingDistance = Distance, RemainingVarElements = VarElements, NextLength = RemainingDistance / VarElements; // removed ' - FixedLength'
22253 
22254  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
22255  {
22256  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(168, x);
22257  TTrackElement & TE = Track->TrackElementAt(35, Track->GetVectorPositionFromTrackMap(29, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
22258 // if(!Track->IsPlatformOrNamedNonStationLocationPresent(4, TE.HLoc, TE.VLoc)) //variable lengths dropped in v2.4.0
22259 // {
22260  if(NextLength < 10)
22261  {
22262  NextLength = 10; // added for safety
22263  }
22264  if(TE.TrackType == Points)
22265  {
22266  if((PrefDirElement.GetELinkPos() == 1) || (PrefDirElement.GetXLinkPos() == 1))
22267  {
22268  TE.Length01 = NextLength;
22269  }
22270  else
22271  {
22272  TE.Length23 = NextLength;
22273  }
22274  }
22275  else
22276  {
22277  if(PrefDirElement.GetELinkPos() < 2)
22278  {
22279  TE.Length01 = NextLength;
22280  }
22281  else
22282  {
22283  TE.Length23 = NextLength;
22284  }
22285  }
22286  RemainingDistance -= NextLength;
22287  RemainingVarElements--;
22288  if(RemainingVarElements > 0)
22289  {
22290  NextLength = RemainingDistance / RemainingVarElements;
22291  }
22292  else
22293  {
22294  NextLength = 10;
22295  }
22296 /* removed these as using integer division & that sometimes problematic. None of these errors ever reported but be safe
22297  if((RemainingDistance == 0) && (RemainingVarElements != 0))
22298  {
22299  throw Exception("Error RemainingDistance == 0 & RemainingVarElements != 0");
22300  }
22301  if((RemainingDistance != 0) && (RemainingVarElements == 0))
22302  {
22303  throw Exception("Error RemainingDistance != 0 & RemainingVarElements == 0");
22304  }
22305 */
22306 // }
22307  }
22308  Utilities->CallLogPop(614);
22309 }
22310 
22311 // ---------------------------------------------------------------------------
22312 
22314 {
22315  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveAsSubroutine");
22317  {
22318  ShowMessage("Nothing to save!");
22319  }
22320  else
22321  {
22322  if(Track->IsReadyForOperation(false))
22323  {
22324  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly";
22325  }
22326  else
22327  {
22328  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev";
22329  }
22330  if(SaveRailwayDialog->Execute())
22331  {
22332  if(SaveRailwayDialog->InitialDir != TPath::GetDirectoryName(SaveRailwayDialog->FileName)) // new at v2.6.0 to retain a new directory
22333  {
22334  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
22335  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
22336  }
22337  Screen->Cursor = TCursor(-11); // Hourglass;
22338  TrainController->LogEvent("Save " + SaveRailwayDialog->FileName);
22339  AnsiString Extension = "";
22340  if(SaveRailwayDialog->FileName.Length() > 2)
22341  {
22342  Extension = AnsiString(SaveRailwayDialog->FileName).SubString(AnsiString(SaveRailwayDialog->FileName).Length() - 2, 3).UpperCase();
22343  }
22344  if((Extension == "DEV") || (Track->IsReadyForOperation(true) && (Extension == "RLY"))) // give duplicated location name message if appropriate
22345  {
22346  std::ofstream VecFile(AnsiString(SaveRailwayDialog->FileName).c_str());
22347  if(!(VecFile.fail()))
22348  {
22352  // save track elements
22353  if(Track->UserGraphicVector.empty())
22354  {
22355  Track->SaveTrack(1, VecFile, false); // false for no graphics (**Active elements** saved as marker)
22356  }
22357  else
22358  {
22359  Track->SaveTrack(13, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
22360  }
22361  // save text elements
22362  TextHandler->SaveText(1, VecFile);
22363  // save PrefDir elements
22364  EveryPrefDir->SavePrefDirVector(1, VecFile);
22365  if(!Track->UserGraphicVector.empty())
22366  {
22367  // save user graphics
22368  Track->SaveUserGraphics(4, VecFile);
22369  }
22370  VecFile.close();
22371  SavedFileName = SaveRailwayDialog->FileName; // includes the full PrefDir
22372  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
22373  {
22374  char LastChar = SavedFileName[SavedFileName.Length()];
22375  if((LastChar == 'y') || (LastChar == 'Y'))
22376  {
22377  RlyFile = true;
22378  }
22379  else
22380  {
22381  RlyFile = false;
22382  }
22383  }
22384  else
22385  {
22386  RlyFile = false;
22387  }
22388  FileChangedFlag = false;
22389  for(int x = SaveRailwayDialog->FileName.Length(); x > 0; x--)
22390  {
22391  if(SaveRailwayDialog->FileName[x] == '\\')
22392  {
22393  RailwayTitle = SaveRailwayDialog->FileName.SubString(x + 1, SaveRailwayDialog->FileName.Length() - x - 4);
22394  // TimetableTitle = ""; leave this as is, no need to unload a tt just because saved railway
22395  SetCaption(7);
22396  break;
22397  }
22398  }
22399  Level1Mode = BaseMode;
22400  SetLevel1Mode(13); // to disable the save option
22401  } // if(!(VecFile.fail()))
22402  else
22403  {
22404  ShowMessage("File open failed prior to save");
22405  }
22406  } // else following if(!Track->IsReadyForOperation() && (Extension != "DEV"))
22407  else
22408  {
22409  ShowMessage("Can't save: extension must be either '.dev', or '.rly' with railway ready for operation");
22410  }
22411  Screen->Cursor = TCursor(-2); // Arrow
22412  } // if(SaveRailwayDialog->Execute())
22413 
22414  }
22415  session_api_->dump(); // update session INI file //added at v2.10.0
22416  Utilities->CallLogPop(1546);
22417 }
22418 
22419 // ---------------------------------------------------------------------------
22420 
22422 {
22423  try
22424  {
22425  // no need for log as only setting values
22426  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackModeEditMenu");
22427  CutMenuItem->Visible = true;
22428  CopyMenuItem->Visible = true;
22429  FlipMenuItem->Visible = true;
22430  MirrorMenuItem->Visible = true;
22431  RotRightMenuItem->Visible = true;
22432  RotLeftMenuItem->Visible = true;
22433  RotateMenuItem->Visible = true;
22434  PasteMenuItem->Visible = true;
22435  DeleteMenuItem->Visible = true;
22436  SelectLengthsMenuItem->Visible = true;
22437  ReselectMenuItem->Visible = true;
22438  // Application->MessageBox(L"Running SetTrackModeEditMenu", L"Message", MB_OK); //debug check
22439  CutMenuItem->Enabled = false;
22440  CopyMenuItem->Enabled = false;
22441  FlipMenuItem->Enabled = false;
22442  MirrorMenuItem->Enabled = false;
22443  RotRightMenuItem->Enabled = false;
22444  RotLeftMenuItem->Enabled = false;
22445  RotateMenuItem->Enabled = false;
22446  PasteMenuItem->Enabled = false;
22447  EditMenu->Enabled = false;
22448  System::WideChar ValidityBuffer[14];
22449  Clipboard()->GetTextBuf(ValidityBuffer, 14);
22450  ClpBrdValid = AnsiString(ValidityBuffer);
22451  Clipboard()->Close();
22452 
22453  // new section for 2.8.0 in case have valid clipboard from another application
22454  if(!SelectionValid)
22455  {
22456  if(ClpBrdValid == "RlyClpBrdCopy")
22457  {
22458  PasteMenuItem->Enabled = true;
22459  if(Level1Mode == TrackMode)
22460  {
22461  EditMenu->Enabled = true;
22462  }
22463  CopySelected = true;
22464  Track->CopyFlag = true;
22465  // Level1Mode = TrackMode;
22466  }
22467  else if(ClpBrdValid == "RlyClpBrd_Cut")
22468  {
22469  PasteMenuItem->Enabled = true;
22470  if(Level1Mode == TrackMode)
22471  {
22472  EditMenu->Enabled = true;
22473  }
22474  CopySelected = false;
22475  Track->CopyFlag = false;
22476  // Level1Mode = TrackMode;
22477  }
22478  }
22479  // end of new section
22480 
22481  // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 (dropped at 2.4.0 as all pastes are with attributes)
22482  ClpBrdValid = "";
22483  DeleteMenuItem->Enabled = false;
22484  SelectLengthsMenuItem->Enabled = false;
22485  if(SelectionValid)
22486  {
22487  ReselectMenuItem->Enabled = true;
22488  }
22489  else
22490  {
22491  ReselectMenuItem->Enabled = false;
22492  }
22493  SelectBiDirPrefDirsMenuItem->Visible = false;
22494  CheckPrefDirConflictsMenuItem->Visible = false;
22495  CancelSelectionMenuItem->Enabled = true;
22496  SelectMenuItem->Enabled = true;
22497 
22498  if(NoRailway() && (TrackElementPanel->Visible == false)) //added latter condition at v2.10.0 so can use select to add track elements in bulk
22499  {
22500  SelectMenuItem->Enabled = false;
22501  }
22502  else if(Level1Mode == TrackMode)
22503  {
22504  EditMenu->Enabled = true;
22505  }
22506  Utilities->CallLogPop(2273);
22507  }
22508  catch(const EClipboardException &e) //non-error catch - added at v2.10.0 after SamWainwright access denial error (08/09/21)
22509  //also reported by Bengt on 03/10/21
22510  {
22511  TrainController->LogEvent("EClipboardException in SetTrackModeEditMenu - message = " + e.Message);
22512  Utilities->CallLogPop(2321);
22513  }
22514 }
22515 
22516 // ---------------------------------------------------------------------------
22517 
22519 {
22520  // no need for caller or log as only setting values
22521  EditMenu->Enabled = true;
22522 
22523  CutMenuItem->Visible = false;
22524  CopyMenuItem->Visible = false;
22525  FlipMenuItem->Visible = false;
22526  MirrorMenuItem->Visible = false;
22527  RotRightMenuItem->Visible = false;
22528  RotLeftMenuItem->Visible = false;
22529  RotateMenuItem->Visible = false;
22530  PasteMenuItem->Visible = false;
22531 // PasteWithAttributesMenuItem->Visible = false; //added at v2.2.0 (dropped at 2.4.0 as all pastes are with attributes)
22532  DeleteMenuItem->Visible = false;
22533  SelectLengthsMenuItem->Visible = false;
22534  ReselectMenuItem->Visible = false;
22535 
22536  SelectBiDirPrefDirsMenuItem->Visible = true;
22537  CheckPrefDirConflictsMenuItem->Visible = true;
22538  SelectBiDirPrefDirsMenuItem->Enabled = false;
22539  CheckPrefDirConflictsMenuItem->Enabled = true;
22540  CancelSelectionMenuItem->Enabled = true;
22541  SelectMenuItem->Enabled = true;
22542 }
22543 
22544 // ---------------------------------------------------------------------------
22545 
22547 {
22548  return ((Track->NoActiveOrInactiveTrack(5)) && (TextHandler->TextVectorSize(8) == 0) && Track->UserGraphicVector.empty());
22549 }
22550 
22551 // ---------------------------------------------------------------------------
22552 
22554 {
22555  SelectRect.left = 0;
22556  SelectRect.right = 0;
22557  SelectRect.top = 0;
22558  SelectRect.bottom = 0;
22559 }
22560 
22561 // ---------------------------------------------------------------------------
22562 
22563 bool TInterface::EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
22564 {
22565  // return position of erased name in HPos & VPos, return true for found & erased
22566  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationNameText," + Name);
22567  bool TextFound = false;
22568 
22569 // if(Track->LocationNameMultiMap.find(Name) == Track->LocationNameMultiMap.end()) {} //name not in LocationNameMultiMap, so don't erase from TextVector //condition dropped at v1.1.4 because of change in EnterLocationNames
22570 /* else */ if(TextHandler->FindText(0, Name, HPos, VPos))
22571  {
22572  if(TextHandler->TextErase(4, HPos, VPos, Name))
22573  {
22574  ;
22575  } // condition not used
22576 
22577  TextFound = true;
22578  }
22579  Utilities->CallLogPop(1956);
22580  return(TextFound);
22581 }
22582 
22583 // ---------------------------------------------------------------------------
22584 
22585 void TInterface::AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
22586 {
22587  if(Name == "")
22588  {
22589  return;
22590  }
22591  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddLocationNameText," + Name + "," + AnsiString(HPos) + "," +
22592  AnsiString(VPos) + "," + AnsiString((short)UseEnteredPosition));
22593  int VPosHi, VPosLo, TextPosHi, TextPosLo;
22594  TFont *Font = Display->GetFont();
22595 
22596  if(!UseEnteredPosition)
22597  {
22598  if(!Track->FindHighestLowestAndLeftmostNamedElements(0, Name, VPosHi, VPosLo, HPos))
22599  {
22600  Utilities->CallLogPop(1561);
22601  return;
22602  }
22603  int Depth = abs(Font->Height); // Height may be negative - see C++Builder Help file
22604  TextPosHi = VPosHi + 20; // add depth of track element + 4 pixels
22605  TextPosLo = VPosLo - Depth - 4; // reduce by depth of font + 4 pixels
22606  int ScreenPosHi = (Display->DisplayOffsetV * 16) + 576;
22607  int ScreenPosLo = Display->DisplayOffsetV * 16;
22608  if(TextPosLo >= ScreenPosLo)
22609  {
22610  VPos = TextPosLo; // if Lo value on screen then use that - displays above the location
22611  }
22612  else if(TextPosHi < ScreenPosHi)
22613  {
22614  VPos = TextPosHi;
22615  }
22616  else
22617  {
22618  VPos = ScreenPosLo + 288; // if location extends to or beyond height of screen the display in centre of screen
22619  }
22620  }
22621  TTextItem TI(HPos, VPos, Name, Font);
22622 
22623  TI.Font = Font; // may have been changed in constructor when returned as reference
22624  TextHandler->EnterAndDisplayNewText(1, TI, HPos, VPos);
22625  Utilities->CallLogPop(1558);
22626 }
22627 
22628 // ---------------------------------------------------------------------------
22629 
22630 void TInterface::TestFunction() //triggered by Alt Ctrl 4
22631 {
22632  try
22633  {
22634  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TestFunction");
22635 // throw Exception("Test error"); //generate an error file
22636 
22637 // ElapsedTimeTestFunctionStart = true; //for elapsed time investigations in MasterClockTimer
22638 
22639 
22640 
22641 
22642 // ShowMessage("MissedTicks = " + AnsiString(MissedTicks) + "; TotalTicks = " + AnsiString(TotalTicks));
22643 
22644 //DMIt->second.ServiceReference = TMMIt->second.ServiceReference;
22645 //DMIt->second.RepeatNumber = TMMIt->second.RepeatNumber;
22646 //DMIt->second.TimeToExitSecs = TMMIt->second.TimeToExitSecs;
22647 /*
22648  std::ofstream POBMFile("POBMFile.csv");
22649  TDynamicMap::iterator DMIt;
22650  for(DMIt = DynMapToHost.begin(); DMIt != DynMapToHost.end(); DMIt++)
22651  {
22652  POBMFile << DMIt->first.first << ',' << DMIt->first.second << ',' << DMIt->second.ServiceReference << ','
22653  << DMIt->second.RepeatNumber << ',' << DMIt->second.TimeToExitSecs << '\n';
22654  }
22655  POBMFile.close();
22656 */
22657 
22658 /*
22659  std::ifstream ExitFile("ExitFile.txt");
22660  std::ofstream OutMapFile1("OutMapFile1.csv");
22661  std::ofstream OutMapFile2("OutMapFile2.csv");
22662  std::ofstream OutBufFile1("OutBufFile1.csv");
22663  std::ofstream OutBufFile2("OutBufFile2.csv");
22664  AnsiString UserName = "";
22665  unsigned char marker;
22666  TDynamicMap DMap1, DMap2;
22667  TDynamicMap::iterator DMIt;
22668  TBytes Buffer1, Buffer2;
22669  DMap1.clear();
22670  BuildDummyTestMap(DMap1, ExitFile); //for Dan's Waterloo
22671  UpdateDynamicMapFromTimeToExitMultiMap(2, DMap1);
22672 //DMap out
22673  for(DMIt = DMap1.begin(); DMIt != DMap1.end(); DMIt++)
22674  {
22675  OutMapFile1 << DMIt->first.first << ',' << DMIt->first.second.first << ',' << DMIt->first.second.second << ',' << DMIt->second.ServiceReference << ','
22676  << DMIt->second.RepeatNumber << ',' << DMIt->second.TimeToExitSecs << '\n';
22677  }
22678 //end of DMap
22679  BuildDatagramFromPlayerMap(2, '3', "AB", Buffer1, DMap1); //buffer length is set within this function
22680 //Buffer out
22681  OutBufFile1 << Buffer1[0] << ','; //marker
22682  int y = 1;
22683  while((Buffer1[y] != ';') && (y < 5)) //username, upt 4 chars, if less ';' delimiter
22684  {
22685  OutBufFile1 << Buffer1[y];
22686  y++;
22687  }
22688  if(Buffer1[y] == ';')
22689  {
22690  y++;
22691  }
22692  OutBufFile1 << ',';
22693  //y now points to start of DMap data
22694  while(y <= (Buffer1.Length - 9)) //9 bytes allows for ref to be null
22695  {
22696  OutBufFile1 << Buffer1[y] << ',' << Buffer1[y + 1] + (256 * Buffer1[y + 2]) << ',' << Buffer1[y + 3] + (256 * Buffer1[y + 4]) << ',';
22697  y += 5;
22698  int z = 0;
22699  AnsiString ServRef = " ";
22700  while((Buffer1[y + z] != ';') && (z < 8))
22701  {
22702  ServRef[z + 1] = Buffer1[y + z];
22703  z++;
22704  }
22705  ServRef = ServRef.Trim();
22706  OutBufFile1 << ServRef << ',';
22707  y += ServRef.Length();
22708  if(Buffer1[y] == ';')
22709  {
22710  y++;
22711  }
22712  OutBufFile1 << Buffer1[y] + (256 * Buffer1[y + 1]) << ',' << Buffer1[y + 2] + (256 * Buffer1[y + 3]) << '\n';
22713  y += 4;
22714  }
22715 //end of Buffer out
22716  DMap2.clear();
22717  if(BuildDynamicMapFromPlayerDatagram(2, DMap2, Buffer1, marker, UserName)) //startpos = 4 as have '3AB;' a;ready in buffer
22718 //DMap out
22719  {
22720  for(DMIt = DMap2.begin(); DMIt != DMap2.end(); DMIt++)
22721  {
22722  OutMapFile2 << DMIt->first.first << ',' << DMIt->first.second.first << ',' << DMIt->first.second.second << ',' << DMIt->second.ServiceReference << ','
22723  << DMIt->second.RepeatNumber << ',' << DMIt->second.TimeToExitSecs << '\n';
22724  }
22725  //end of DMap out
22726  BuildDatagramFromPlayerMap(3, '4', "ABC", Buffer2, DMap2); //buffer length is set within this function
22727  //Buffer out
22728  OutBufFile2 << Buffer2[0] << ','; //marker
22729  y = 1; //already declared above
22730  while((Buffer2[y] != ';') && (y < 5)) //username, upt 4 chars, if less ';' delimiter
22731  {
22732  OutBufFile2 << Buffer2[y];
22733  y++;
22734  }
22735  if(Buffer2[y] == ';')
22736  {
22737  y++;
22738  }
22739  OutBufFile2 << ',';
22740  }
22741  else
22742  {
22743  ShowMessage("Error in BuildDynamicMapFromPlayerDatagram for DMap2 construction");
22744  }
22745  //y now points to start of DMap data
22746  while(y <= (Buffer2.Length - 9)) //9 bytes allows for ref to be null
22747  {
22748  OutBufFile2 << Buffer2[y] << ',' << Buffer2[y + 1] + (256 * Buffer2[y + 2]) << ',' << Buffer2[y + 3] + (256 * Buffer2[y + 4]) << ',';
22749  y += 5;
22750  int z = 0;
22751  AnsiString ServRef = " ";
22752  while((Buffer2[y + z] != ';') && (z < 8))
22753  {
22754  ServRef[z + 1] = Buffer2[y + z];
22755  z++;
22756  }
22757  ServRef = ServRef.Trim();
22758  OutBufFile2 << ServRef << ',';
22759  y += ServRef.Length();
22760  if(Buffer2[y] == ';')
22761  {
22762  y++;
22763  }
22764  OutBufFile2 << Buffer2[y] + (256 * Buffer2[y + 1]) << ',' << Buffer2[y + 2] + (256 * Buffer2[y + 3]) << '\n';
22765  y += 4;
22766  }
22767 //end of Buffer out
22768 
22769  ExitFile.close();
22770  OutMapFile1.close();
22771  OutMapFile2.close();
22772  OutBufFile1.close();
22773  OutBufFile2.close();
22774 */
22775 
22776 /*
22777  for(DMIt = DMap1.begin(); DMIt != DMap1.end(); DMIt++)
22778  {
22779  OutMapFile << DMIt->first.first << ',' << DMIt->first.second << ',' << DMIt->second.ServiceReference << ','
22780  << DMIt->second.RepeatNumber << ',' << DMIt->second.TimeToExitSecs << '\n';
22781  }
22782  */
22783 
22784 /*
22785  TCouplingMap::iterator CMMIt;
22786  std::ofstream CMOutFile("CMOutFile.txt");
22787  for(CMMIt = CouplingMap.begin(); CMMIt != CouplingMap.end(); CMMIt++)
22788  {
22789  CMOutFile << CMMIt->first.first.RailwayName << ';' << CMMIt->first.second.first << '-' << CMMIt->first.second.second << ';'
22790  << CMMIt->second.first.RailwayName << ';' << CMMIt->second.second.first << '-' << CMMIt->second.second.second << '\n';
22791  }
22792  CMOutFile.close();
22793 */
22794  Utilities->CallLogPop(2376);
22795  }
22796  catch(const Exception &e)
22797  {
22798  ErrorLog(114, e.Message);
22799  }
22800 }
22801 
22802 // ---------------------------------------------------------------------------
22803 
22805 {
22806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
22815  Utilities->CallLogPop(1871);
22816 }
22817 
22818 // ---------------------------------------------------------------------------
22819 
22820 void TInterface::LoadGroundSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
22821 {
22822  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
22831  Utilities->CallLogPop(1872);
22832 }
22833 
22834 // ---------------------------------------------------------------------------
22835 
22836 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
22837 // limit it to 20 entries max
22838 {
22839  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
22841  {
22842  OAListBox->Clear();
22843  }
22845  // new at v2.2.0
22846  {
22847  Utilities->CallLogPop(2092);
22848  return;
22849  }
22850  AnsiString OpTimeToActDisplay;
22851  AnsiString OpTimeToActString;
22852  AnsiString HeadCode;
22853  float OpTimeToActFloat;
22854  TTrainController::THCandTrainPosParam HCandTrainPosParam;
22855 
22858  {
22859  if(OAListBox->Items->Count >= 20)
22860  {
22861  break;
22862  }
22863  OpTimeToActFloat = TrainController->OpTimeToActMultiMapIterator->first;
22864  HCandTrainPosParam = TrainController->OpTimeToActMultiMapIterator->second;
22865  HeadCode = HCandTrainPosParam.first;
22866  if(OpTimeToActFloat < 0.25) // 15 secs estimated
22867  {
22868  OpTimeToActString = "NOW";
22869  }
22870  else if(OpTimeToActFloat < 1)
22871  {
22872  OpTimeToActString = "<1";
22873  }
22874  else
22875  {
22876  OpTimeToActString = AnsiString(floor(OpTimeToActFloat));
22877  }
22878  if(OpTimeToActFloat < 60)
22879  {
22880  OpTimeToActDisplay = HeadCode + AnsiString('\t') + OpTimeToActString;
22881  OAListBox->Items->Add(OpTimeToActDisplay); // original
22882  }
22884  }
22885  Utilities->CallLogPop(2093);
22886 }
22887 
22888 // ---------------------------------------------------------------------------
22889 //below used in debugging TimeToExitMultiMap: replaces times to act in OpTimeToAct panel with headcodes and exit times (or exit locs) so they are visible
22890 //to use, uncomment this function and comment out the original above
22891 /*
22892 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
22893 // limit it to 20 entries max
22894 {
22895  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
22896  if(TrainController->OpActionPanelHintDelayCounter >= 60)
22897  {
22898  OAListBox->Clear();
22899  }
22900  if((!OperatorActionPanel->Visible) || TrainController->TimeToExitMultiMap.empty() || (TrainController->OpActionPanelHintDelayCounter < 60))
22901  // new at v2.2.0
22902  {
22903  Utilities->CallLogPop(2386);
22904  return;
22905  }
22906  AnsiString OpTimeToActDisplay;
22907  AnsiString OpTimeToActString;
22908  AnsiString HeadCode;
22909  THVShortPair ExitPair;
22910  float OpTimeToActFloat;
22911 // TTrainController::THCandTrainPosParam HCandTrainPosParam;
22912 
22913  TTimeToExitMultiMap::iterator TTEMMIt = TrainController->TimeToExitMultiMap.begin();
22914  while(TTEMMIt != TrainController->TimeToExitMultiMap.end())
22915  {
22916  if(OAListBox->Items->Count >= 20)
22917  {
22918  break;
22919  }
22920  OpTimeToActFloat = float(TTEMMIt->second.TimeToExitSecs);
22921  HeadCode = TTEMMIt->second.ServiceReference.Trim();
22922  ExitPair = TTEMMIt->first;
22923  if((OpTimeToActFloat > 0) && (OpTimeToActFloat < 3600)) //no display if outside these limits
22924  {
22925  OpTimeToActString = AnsiString(int(OpTimeToActFloat));//seconds
22926  OpTimeToActDisplay = HeadCode + AnsiString(' ') + OpTimeToActString; //comment out one of these to display times or exits
22927  OAListBox->Items->Add(OpTimeToActDisplay);
22928  }
22929  TTEMMIt++;
22930  }
22931  Utilities->CallLogPop(2377;
22932 }
22933 */
22934 // ---------------------------------------------------------------------------
22935 
22936 void TInterface::LoadUserGraphic(int Caller) // new at v2.4.0
22937 {
22938  try
22939  {
22940  TrainController->LogEvent("LoadUserGraphic");
22941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadUserGraphic");
22942  if(LoadUserGraphicDialog->Execute())
22943  {
22944  TrainController->LogEvent("LoadUserGraphic " + LoadUserGraphicDialog->FileName);
22945  SelectedGraphicFileName = AnsiString(LoadUserGraphicDialog->FileName); // SelectedGraphicFileName is a class member
22947  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
22948  if(UGMIt == Track->UserGraphicMap.end()) // i.e. there isn't an entry for that filename so insert one, else take no action
22949  {
22950  UGME.first = SelectedGraphicFileName;
22951  TPicture *PicPtr = new TPicture;
22952  PicPtr->LoadFromFile(SelectedGraphicFileName);
22953  UGME.second = PicPtr;
22954  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
22955  {
22956  throw Exception("Map Insertion Error 1 - UserGraphicMap insertion failure for " + SelectedGraphicFileName);
22957  }
22958  }
22960  SetLevel2TrackMode(65);
22961  }
22962  Utilities->CallLogPop(2191);
22963  }
22964  catch(const EInvalidGraphic &e) //non-error catch
22965  {
22966  ShowMessage(
22967  "Incorrect file format, the file can't be loaded.\nEnsure that the file you want is a valid graphic file with extension .bmp, .gif, .jpg, or .png");
22968  Utilities->CallLogPop(2311);
22969  }
22970  catch(const Exception &e)
22971  {
22972  ErrorLog(215, e.Message);
22973  }
22974 }
22975 
22976 // ---------------------------------------------------------------------------
22977 
22978 void TInterface::LoadClipboard(int Caller) // new at v2.8.0
22979 {
22980  try
22981  {
22982  TrainController->LogEvent("LoadClipboard");
22983  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadClipboard");
22984 
22985  std::wstringstream wss; // used to hold all parameters prior to conversion to a string buffer
22986  if(CopySelected)
22987  {
22988  wss << "RlyClpBrdCopy\n";
22989  }
22990  else
22991  {
22992  wss << "RlyClpBrd_Cut\n";
22993  }
22994 // Load the active & inactive track vectors
22995  for(TTrack::TTrackVectorIterator TTVIt = Track->SelectVector.begin(); TTVIt < Track->SelectVector.end(); TTVIt++)
22996  {
22997  wss << TTVIt->SpeedTag;
22998  wss << '\n'; // inherited int - all FixedTrackPiece parameters implicit in this
22999  for(int AnsLen = 0; AnsLen <= TTVIt->ActiveTrackElementName.Length(); AnsLen++)
23000  {
23001  if((TTVIt->ActiveTrackElementName).c_str()[AnsLen] != '\0')
23002  {
23003  wss << (TTVIt->ActiveTrackElementName).c_str()[AnsLen];
23004  }
23005  else
23006  {
23007  wss << '\n';
23008  }
23009  }
23010  for(int AnsLen = 0; AnsLen <= TTVIt->ElementID.Length(); AnsLen++)
23011  {
23012  if((TTVIt->ElementID).c_str()[AnsLen] != '\0')
23013  {
23014  wss << (TTVIt->ElementID).c_str()[AnsLen];
23015  }
23016  else
23017  {
23018  wss << '\n';
23019  }
23020  }
23021  for(int AnsLen = 0; AnsLen <= TTVIt->LocationName.Length(); AnsLen++)
23022  {
23023  if((TTVIt->LocationName).c_str()[AnsLen] != '\0')
23024  {
23025  wss << (TTVIt->LocationName).c_str()[AnsLen];
23026  }
23027  else
23028  {
23029  wss << '\n';
23030  }
23031  }
23032  wss << TTVIt->CallingOnSet;
23033  wss << '\n';
23034  wss << TTVIt->LCPlotted;
23035  wss << '\n';
23036  wss << TTVIt->TempTrackMarker01;
23037  wss << '\n';
23038  wss << TTVIt->TempTrackMarker23;
23039  wss << '\n';
23040  wss << TTVIt->Attribute;
23041  wss << '\n'; // all ints from here except last which is an enum
23042  wss << TTVIt->Conn[0];
23043  wss << '\n';
23044  wss << TTVIt->Conn[1];
23045  wss << '\n';
23046  wss << TTVIt->Conn[2];
23047  wss << '\n';
23048  wss << TTVIt->Conn[3];
23049  wss << '\n';
23050  wss << TTVIt->ConnLinkPos[0];
23051  wss << '\n';
23052  wss << TTVIt->ConnLinkPos[1];
23053  wss << '\n';
23054  wss << TTVIt->ConnLinkPos[2];
23055  wss << '\n';
23056  wss << TTVIt->ConnLinkPos[3];
23057  wss << '\n';
23058  wss << TTVIt->HLoc;
23059  wss << '\n';
23060  wss << TTVIt->VLoc;
23061  wss << '\n';
23062  wss << TTVIt->Length01;
23063  wss << '\n';
23064  wss << TTVIt->Length23;
23065  wss << '\n';
23066  wss << TTVIt->SpeedLimit01;
23067  wss << '\n';
23068  wss << TTVIt->SpeedLimit23;
23069  wss << '\n';
23070  wss << TTVIt->StationEntryStopLinkPos1;
23071  wss << '\n';
23072  wss << TTVIt->StationEntryStopLinkPos2;
23073  wss << '\n';
23074  wss << TTVIt->TrainIDOnElement;
23075  wss << '\n';
23076  wss << TTVIt->TrainIDOnBridgeTrackPos01;
23077  wss << '\n';
23078  wss << TTVIt->TrainIDOnBridgeTrackPos23;
23079  wss << '\n';
23080  wss << int(TTVIt->SigAspect);
23081  wss << '\n'; // enum
23082  }
23083  wss << "$$$" << '\n'; // send track element end marker
23084 
23085 // Load the text vector
23086 
23087  for(TTextHandler::TTextVectorIterator TTVIt = TextHandler->SelectTextVector.begin(); TTVIt < TextHandler->SelectTextVector.end(); TTVIt++)
23088  {
23089  for(int AnsLen = 0; AnsLen <= TTVIt->TextString.Length(); AnsLen++)
23090  {
23091  if((TTVIt->TextString).c_str()[AnsLen] != '\0')
23092  {
23093  wss << (TTVIt->TextString).c_str()[AnsLen];
23094  }
23095  else
23096  {
23097  wss << '\n';
23098  }
23099  }
23100  wss << TTVIt->HPos;
23101  wss << '\n';
23102  wss << TTVIt->VPos;
23103  wss << '\n';
23104  for(int AnsLen = 0; AnsLen <= AnsiString(TTVIt->Font->Name).Length(); AnsLen++)
23105  {
23106  if(AnsiString(TTVIt->Font->Name).c_str()[AnsLen] != '\0')
23107  {
23108  wss << AnsiString(TTVIt->Font->Name).c_str()[AnsLen];
23109  }
23110  else
23111  {
23112  wss << '\n';
23113  }
23114  }
23115  wss << TTVIt->Font->Size;
23116  wss << '\n';
23117  if((TTVIt->Font->Color < 0) || (TTVIt->Font->Color > 0xFFFFFF)) // if set to any of the special 'windows' colours save it as black
23118  {
23119  wss << "0\n";
23120  }
23121  else
23122  {
23123  wss << int(TTVIt->Font->Color) << '\n';
23124  }
23125  wss << int(TTVIt->Font->Charset) << '\n'; // save as 'int' (would be unsigned char else) so 'n' can act as proper delimiter
23126  wss << TextHandler->GetFontStyleAsInt(1, TTVIt->Font) << '\n';
23127  }
23128  wss << "$$$" << '\n'; // send text item end marker
23129 
23130  //load select dimensions
23131  wss << SelectBitmap->Height;
23132  wss << '\n';
23133  wss << SelectBitmap->Width;
23134  wss << '\n';
23135  wss << SelectRect.left;
23136  wss << '\n';
23137  wss << SelectRect.top;
23138  wss << '\n';
23139  wss << "$$$" << '\n'; // send end of select dimension marker
23140 
23141  //load preferred directions //added at v2.9.0
23142  if(SelectPrefDir->PrefDirSize() > 0) // skip load if empty
23143  {
23144  for(TOnePrefDir::TPrefDirVectorIterator PDVIt = SelectPrefDir->PrefDirVector.begin(); PDVIt < SelectPrefDir->PrefDirVector.end(); PDVIt++)
23145  {
23146  //Note that TrackVector Position won't be valid for a remote paste, it will be reset when pasted, also Conns & ConnLinkPosses set when
23147  //track linked
23148  wss << PDVIt->GetTrackVectorPosition(); //added at v2.9.2 so all 9 of CheckCount properties loaded (SpeedTag loaded from TrackElement at HLoc & VLoc)
23149  wss << '\n';
23150  wss << PDVIt->GetHLoc();
23151  wss << '\n';
23152  wss << PDVIt->GetVLoc();
23153  wss << '\n';
23154  wss << PDVIt->GetELink();
23155  wss << '\n';
23156  wss << PDVIt->GetELinkPos();
23157  wss << '\n';
23158  wss << PDVIt->GetXLink();
23159  wss << '\n';
23160  wss << PDVIt->GetXLinkPos();
23161  wss << '\n';
23162  wss << PDVIt->GetEXNumber();
23163  wss << '\n';
23164  }
23165  }
23166  wss << "$$$" << '\n'; // send pref dir end marker
23167  wss << '\0'; // has to end with NULL
23168 
23169  Clipboard()->Clear(); // clear the clipboard
23170  Clipboard()->SetTextBuf(&(wss.str()[0])); // populate the clipboard
23171  Clipboard()->Close();
23172 
23173  Utilities->CallLogPop(2267);
23174  }
23175 
23176  catch(const EClipboardException &e) //non-error catch - ignore access denials (but only seems to happen with recover), doesn't affect program
23177  {
23178 // Application->MessageBox(L"A clipboard error occurred in loading the clipboard", L"Message", MB_OK);
23179  TrainController->LogEvent("EClipboardException in LoadClipboard - message = " + e.Message);
23180  Utilities->CallLogPop(2312);
23181  }
23182 
23183  catch(const Exception &e)
23184  {
23185  ErrorLog(222, e.Message);
23186  }
23187 
23188 }
23189 
23190 // ---------------------------------------------------------------------------
23191 
23192 void TInterface::RecoverClipboard(int Caller, bool &ValidResult) // new at v2.8.0
23193 {
23194  try
23195  {
23196  TrainController->LogEvent("RecoverClipboard");
23197  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RecoverClipboard");
23198  ValidResult = false;
23199  System::WideChar *SelectVectorBuffer = new System::WideChar[4000000]; // scope for 130 chars per element & 4k resolution (240 x 135 elements)
23200  int StreamSize = 0;
23201  StreamSize = Clipboard()->GetTextBuf(SelectVectorBuffer, 4000000);
23202  Clipboard()->Clear(); // clear it so can't keep pasting same thing as don't permit this in single app
23203  Clipboard()->Close();
23204  if(StreamSize < 14)
23205  {
23206  Utilities->CallLogPop(2270); // ValidResult == false
23207  return;
23208  }
23209  std::wstringstream wss;
23210  wss << SelectVectorBuffer;
23211  ClpBrdValid = AnsiString(SelectVectorBuffer).SubString(1, 13);
23212  PasteMenuItem->Enabled = false;
23213  delete[]SelectVectorBuffer;
23214 
23215  if((ClpBrdValid != AnsiString("RlyClpBrdCopy")) && (ClpBrdValid != AnsiString("RlyClpBrd_Cut")))
23216  {
23217  Utilities->CallLogPop(2268); // ValidResult == false
23218  return;
23219  }
23220  int MarkerCounter = 0; //If ever get a MarkerCounter value well outside expected range it's probably because some text is too long - see comment below
23221  ClpBrdValid = "";
23222  wchar_t LineString[1000]; // should be big enough for any entry, (extended from 100 at v2.9.2) text can be long but hopefully not this long - won't
23223  //recover the clipboard if longer but won't crash. It has to be at least as big as the biggest getline number or the excess will overwrite other variables,
23224  //this was discovered when MarkerCounter suddenly jumped from 1 to nearly 3000000 when Linesting loaded with text ~180 chars long with LineString limited
23225  //to 100 chars
23226 
23227  wss.getline(LineString, 100); // RlyClpBrdCopy or ...Cut - discard it
23228  Track->SelectVector.clear();
23229  TTrack::TTrackMap SelectTrackMap; //build map so can find TrackElement at required H & V to build PrefDirElement from it //added at v2.9.0
23230  THVShortPair SelectTrackMapKeyPair; //for above
23231  TTrack::TTrackMapEntry SelectTrackMapEntry; //for above
23232  while(true) // recover active & inactive track (active first & top to bottom at leftmost position then again stepping right
23233  {
23234  wss.getline(LineString, 100);
23235  if(AnsiString(LineString) == "$$$") // end of track element marker
23236  {
23237  MarkerCounter++;
23238  break;
23239  }
23240  // if not $$$ then it's the SpeedTag number
23241  TTrackElement TE = Track->BuildBasicElementFromSpeedTag(5, AnsiString(LineString).ToInt());
23242  wss.getline(LineString, 100);
23243  TE.ActiveTrackElementName = AnsiString(LineString); // if not "$$$" must be the start of the next element
23244  wss.getline(LineString, 100);
23245  TE.ElementID = AnsiString(LineString);
23246  wss.getline(LineString, 100);
23247  TE.LocationName = AnsiString(LineString);
23248 
23249  wss.getline(LineString, 100);
23250  TE.CallingOnSet = AnsiString(LineString).ToInt();
23251  wss.getline(LineString, 100);
23252  TE.LCPlotted = AnsiString(LineString).ToInt();
23253  wss.getline(LineString, 100);
23254  TE.TempTrackMarker01 = AnsiString(LineString).ToInt();
23255  wss.getline(LineString, 100);
23256  TE.TempTrackMarker23 = AnsiString(LineString).ToInt();
23257 
23258  wss.getline(LineString, 100);
23259  TE.Attribute = AnsiString(LineString).ToInt();
23260  wss.getline(LineString, 100);
23261  TE.Conn[0] = AnsiString(LineString).ToInt();
23262  wss.getline(LineString, 100);
23263  TE.Conn[1] = AnsiString(LineString).ToInt();
23264  wss.getline(LineString, 100);
23265  TE.Conn[2] = AnsiString(LineString).ToInt();
23266  wss.getline(LineString, 100);
23267  TE.Conn[3] = AnsiString(LineString).ToInt();
23268  wss.getline(LineString, 100);
23269  TE.ConnLinkPos[0] = AnsiString(LineString).ToInt();
23270  wss.getline(LineString, 100);
23271  TE.ConnLinkPos[1] = AnsiString(LineString).ToInt();
23272  wss.getline(LineString, 100);
23273  TE.ConnLinkPos[2] = AnsiString(LineString).ToInt();
23274  wss.getline(LineString, 100);
23275  TE.ConnLinkPos[3] = AnsiString(LineString).ToInt();
23276  wss.getline(LineString, 100);
23277  TE.HLoc = AnsiString(LineString).ToInt();
23278  wss.getline(LineString, 100);
23279  TE.VLoc = AnsiString(LineString).ToInt();
23280  wss.getline(LineString, 100);
23281  TE.Length01 = AnsiString(LineString).ToInt();
23282  wss.getline(LineString, 100);
23283  TE.Length23 = AnsiString(LineString).ToInt();
23284  wss.getline(LineString, 100);
23285  TE.SpeedLimit01 = AnsiString(LineString).ToInt();
23286  wss.getline(LineString, 100);
23287  TE.SpeedLimit23 = AnsiString(LineString).ToInt();
23288  wss.getline(LineString, 100);
23289  TE.StationEntryStopLinkPos1 = AnsiString(LineString).ToInt();
23290  wss.getline(LineString, 100);
23291  TE.StationEntryStopLinkPos2 = AnsiString(LineString).ToInt();
23292  wss.getline(LineString, 100);
23293  TE.TrainIDOnElement = AnsiString(LineString).ToInt();
23294  wss.getline(LineString, 100);
23295  TE.TrainIDOnBridgeTrackPos01 = AnsiString(LineString).ToInt();
23296  wss.getline(LineString, 100);
23297  TE.TrainIDOnBridgeTrackPos23 = AnsiString(LineString).ToInt();
23298 
23299  wss.getline(LineString, 100);
23300  int temp = AnsiString(LineString).ToInt();
23301  if(temp == 0)
23302  {
23304  }
23305  else if(temp == 1)
23306  {
23308  }
23309  else if(temp == 2)
23310  {
23312  }
23313  else if(temp == 3)
23314  {
23316  }
23317  Track->SelectVector.push_back(TE);
23318  if((TE.TrackType != Concourse) && (TE.TrackType != Parapet) && (TE.TrackType != NamedNonStationLocation) && (TE.TrackType != Platform)
23319  && (TE.TrackType != LevelCrossing)) //aded at v2.9.2 so only active elements added to SelectTrackMap
23320  {
23321  SelectTrackMapKeyPair.first = TE.HLoc;
23322  SelectTrackMapKeyPair.second = TE.VLoc;
23323  SelectTrackMapEntry.first = SelectTrackMapKeyPair;
23324  SelectTrackMapEntry.second = Track->SelectVector.size() - 1;
23325  SelectTrackMap.insert(SelectTrackMapEntry);
23326  }
23327  }
23328 
23329  TextHandler->SelectTextVector.clear();
23330  AnsiString FontName;
23331  int FontSize, FontColour, FontCharset, FontStyle;
23332  while(true) // recover text
23333  {
23334  wss.getline(LineString, 1000);
23335  if(AnsiString(LineString) == "$$$") // end of text marker
23336  {
23337  MarkerCounter++;
23338  break;
23339  }
23340  // if not $$$ then it's the text string
23341  TTextItem TI;
23342  TI.TextString = AnsiString(LineString);
23343  wss.getline(LineString, 1000); //extended to 1000 from 100 for text items at v2.9.2
23344  TI.HPos = AnsiString(LineString).ToInt();
23345  wss.getline(LineString, 1000);
23346  TI.VPos = AnsiString(LineString).ToInt();
23347  wss.getline(LineString, 1000);
23348  FontName = AnsiString(LineString).c_str();
23349  wss.getline(LineString, 1000);
23350  FontSize = AnsiString(LineString).ToInt();
23351  wss.getline(LineString, 1000);
23352  FontColour = AnsiString(LineString).ToInt();
23353  wss.getline(LineString, 1000);
23354  FontCharset = AnsiString(LineString).ToInt();
23355  wss.getline(LineString, 1000);
23356  FontStyle = AnsiString(LineString).ToInt();
23357  // create a new font
23358  TFont *NewFont = new TFont;
23359  NewFont->Name = FontName;
23360  NewFont->Size = FontSize;
23361  NewFont->Color = static_cast<TColor>(FontColour);
23362  NewFont->Charset = FontCharset;
23363  NewFont->Style = TextHandler->SetFontStyleFromInt(1, FontStyle);
23364  TI.Font = NewFont;
23365  TextHandler->SelectTextVector.push_back(TI);
23366  }
23367 
23368  // recover select dimensions
23369  wss.getline(LineString, 100);
23370  SelectBitmap->Height = AnsiString(LineString).ToInt();
23371  wss.getline(LineString, 100);
23372  SelectBitmap->Width = AnsiString(LineString).ToInt();
23373  wss.getline(LineString, 100);
23374  SelectRect.left = AnsiString(LineString).ToInt();
23375  wss.getline(LineString, 100);
23376  SelectRect.top = AnsiString(LineString).ToInt();
23377  wss.getline(LineString, 100);
23378  if(AnsiString(LineString) == "$$$")
23379  {
23380  MarkerCounter++;
23381  }
23382 
23383  // recover pref dirs - after dimensions so that a clipboard loaded with this app will paste into an earlier version app without pref dirs
23384  // if a clipboard loaded with an earlier app is pasted into this app then the marker will be wrong, an error message will be given but no crash
23385  int TempTVPos, TempHLoc, TempVLoc, TempELink, TempELinkPos, TempXLink, TempXLinkPos, TempEXNumber, ATVecPos;
23386  bool FoundFlag;
23388  while(true)
23389  {
23390  wss.getline(LineString, 100);
23391  if(AnsiString(LineString) == "$$$") // end of pref dir element marker
23392  {
23393  MarkerCounter++;
23394  break;
23395  }
23396  // if not $$$ then it's the TVPos value
23397  TempTVPos = AnsiString(LineString).ToInt(); //added at v2.9.2 so all 9 CheckCount properties valid (SpeedTag loaded from corresponding TrackElement)
23398  wss.getline(LineString, 100);
23399  TempHLoc = AnsiString(LineString).ToInt();
23400  wss.getline(LineString, 100);
23401  TempVLoc = AnsiString(LineString).ToInt();
23402  wss.getline(LineString, 100);
23403  TempELink = AnsiString(LineString).ToInt();
23404  wss.getline(LineString, 100);
23405  TempELinkPos = AnsiString(LineString).ToInt();
23406  wss.getline(LineString, 100);
23407  TempXLink = AnsiString(LineString).ToInt();
23408  wss.getline(LineString, 100);
23409  TempXLinkPos = AnsiString(LineString).ToInt();
23410  wss.getline(LineString, 100);
23411  TempEXNumber = AnsiString(LineString).ToInt();
23412  //build a pref dir element from these values and the corresponding TrackVectorPosition for HLoc & VLoc
23413  TTrackElement TempElement = Track->GetTrackElementFromAnyTrackMap(0, TempHLoc, TempVLoc, SelectTrackMap, Track->SelectVector);
23414  TPrefDirElement TempPrefDirElement(TempElement);
23415 // TempPrefDirElement.HLoc = TempHLoc; //these and SpeedTag already set from TempElement
23416 // TempPrefDirElement.VLoc = TempVLoc;
23417  TempPrefDirElement.SetTrackVectorPosition(TempTVPos); //added at v2.9.2 so all 9 CheckCount properties have values (SpeedTag loaded from corresponding TrackElement)
23418  //TVPos only included for completeness & not valid yet, it will change to the correct value when pasted
23419  //and change again when the track is linked
23420  TempPrefDirElement.SetELink(TempELink);
23421  TempPrefDirElement.SetELinkPos(TempELinkPos);
23422  TempPrefDirElement.SetXLink(TempXLink);
23423  TempPrefDirElement.SetXLinkPos(TempXLinkPos);
23424  TempPrefDirElement.SetEXNumber(TempEXNumber);
23425  TempPrefDirElement.SetCheckCount(9); //added at v2.9.2
23426  SelectPrefDir->ExternalStorePrefDirElement(11, TempPrefDirElement); //added 27/05 at v2.9.0
23427  }
23428 
23429  if(MarkerCounter == 4)
23430  {
23431  ValidResult = true;
23432  }
23433  Utilities->CallLogPop(2269);
23434  }
23435 
23436  catch(const EClipboardException &e) //non-error catch - don't stop for any error in this section, just give bad clipboard message
23437  {
23438  ValidResult = false;
23439  TrainController->LogEvent("EClipboardException in RecoverClipboard - message = " + e.Message);
23440  Utilities->CallLogPop(2313);
23441  }
23442  catch(const Exception &e) //non-error catch - non-clipboard exception
23443  {
23444  ValidResult = false;
23445  TrainController->LogEvent("non-clipboard exception in RecoverClipboard - message = " + e.Message);
23446  Utilities->CallLogPop(2322);
23447 // ErrorLog(223, e.Message);
23448  }
23449 
23450 }
23451 // ---------------------------------------------------------------------------
23452 
23453 void __fastcall TInterface::NoDelaysMenuItemClick(TObject *Sender) //these added at v2.13.0
23454 {
23455  NoDelaysMenuItem->Enabled = false;
23456  MinorDelaysMenuItem->Enabled = true;
23457  ModerateDelaysMenuItem->Enabled = true;
23458  MajorDelaysMenuItem->Enabled = true;
23459  DelayMenu->Caption = "No delays";
23460  Display->PerformanceLog(7777, "No random delays selected");
23461  Utilities->DelayMode = Nil;
23462 }
23463 //---------------------------------------------------------------------------
23464 
23465 void __fastcall TInterface::MinorDelaysMenuItemClick(TObject *Sender)
23466 {
23467  NoDelaysMenuItem->Enabled = true;
23468  MinorDelaysMenuItem->Enabled = false;
23469  ModerateDelaysMenuItem->Enabled = true;
23470  MajorDelaysMenuItem->Enabled = true;
23471  DelayMenu->Caption = "Minor delays";
23472  Display->PerformanceLog(7777, "Minor random delays selected");
23474 }
23475 //---------------------------------------------------------------------------
23476 
23477 void __fastcall TInterface::ModerateDelaysMenuItemClick(TObject *Sender)
23478 {
23479  NoDelaysMenuItem->Enabled = true;
23480  MinorDelaysMenuItem->Enabled = true;
23481  ModerateDelaysMenuItem->Enabled = false;
23482  MajorDelaysMenuItem->Enabled = true;
23483  DelayMenu->Caption = "Moderate delays";
23484  Display->PerformanceLog(7777, "Moderate random delays selected");
23486 }
23487 //---------------------------------------------------------------------------
23488 
23489 void __fastcall TInterface::MajorDelaysMenuItemClick(TObject *Sender)
23490 {
23491  NoDelaysMenuItem->Enabled = true;
23492  MinorDelaysMenuItem->Enabled = true;
23493  ModerateDelaysMenuItem->Enabled = true;
23494  MajorDelaysMenuItem->Enabled = false;
23495  DelayMenu->Caption = "Major delays";
23496  Display->PerformanceLog(7777, "Major random delays selected");
23498 }
23499 
23500 //---------------------------------------------------------------------------
23501 //Multiplayer Code
23502 // ---------------------------------------------------------------------------
23503 
23504 // ---------------------------------------------------------------------------
23505 //Host functions
23506 // ---------------------------------------------------------------------------
23507 
23508 void __fastcall TInterface::MultiplayerHostSessionMenuItemClick(TObject *Sender)
23509 {
23510  try
23511  {
23512  TrainController->LogEvent("MultiplayerHostSessionMenuItemClick");
23513  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MultiplayerHostSessionMenuItemClick");
23514  MultiplayerHostPanel->Visible = true;
23515  MultiplayerHostPanel->Left = MainScreen->Left + (MainScreen->Width / 2) - (MultiplayerHostPanel->Width / 2);
23516  MultiplayerHostPanel->Top = MainScreen->Top + 100;
23517 
23518  MultiplayerHostSessionMenuItem->Enabled = false;
23519  SaveMultiplayerSessionMenuItem->Enabled = false;
23520  EndSimulationMenuItem->Enabled = false;
23521  ShowHideStringGridMenuItem->Enabled = false;
23522  JoinMultiplayerSessionMenuItem->Enabled = false;
23523  ExitSimulationMenuItem->Enabled = false;
23524  HostInSessionFlag = false;
23525  CouplingFileLoadedFlag = false;
23527  PlayerReadyToBeginFlag = false;
23528  PlayerCancelJoinFlag = false;
23530  PlayerInSessionFlag = false;
23531 
23532  MPHPLoadCouplingFileButton->Enabled = false;
23533  MPHPCancelButton->Enabled = true;
23534  MPHPStartButton->Enabled = false;
23535  MPHPGeneralLabel->Caption = "Complete the boxes and press 'Enter' for each.";
23536  MPHPOwnIPEditBox->Text = "0.0.0.0";// <--temporary - change to "" for release
23537  MPHPOwnPortEditBox->Text = "50000";// <--temporary - change to "" for release
23538  MPHPOwnIPEditBox->Enabled = true;
23539  MPHPOwnPortEditBox->Enabled = true;
23540  MPHostClient->Active = false;
23541  Utilities->CallLogPop(2348);
23542  }
23543 
23544  catch(const EIdException &e) //non-error catch
23545  {
23546  ShowMessage("MultiplayerHostSessionMenuItemClick " + e.Message); //<--temporary
23547  Utilities->CallLogPop(2407);
23548  }
23549  catch(const Exception &e)
23550  {
23551  ErrorLog(226, e.Message);
23552  }
23553 }
23554 
23555 //---------------------------------------------------------------------------
23556 
23557 void __fastcall TInterface::MPHPLoadCouplingFileButtonClick(TObject *Sender)
23558 {
23559  try
23560  {
23561  TrainController->LogEvent("MPHPLoadCouplingFileButtonClick");
23562  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPHPLoadCouplingFileButtonClick");
23563  LoadCouplingFileDialog->Filter = "Text file (*.txt)|*.txt";
23564  if(LoadCouplingFileDialog->Execute()) //error messages given in PopulateCouplingMap
23565  {
23566  NumPlayers = 0;
23567  TrainController->LogEvent("LoadCouplingFile " + AnsiString(LoadCouplingFileDialog->FileName));
23568  if(PopulateCouplingMap(AnsiString(LoadCouplingFileDialog->FileName), NumPlayers))
23569  {
23570  MultiplayerHostStringGrid->RowCount = 1; //clear it before loading or reloading
23571  MultiplayerHostStringGrid->ColCount = 1;
23572  MultiplayerHostStringGrid->Cells[0][0] = "";
23574  MultiplayerHostStringGrid->Width = 260;
23576  MultiplayerHostStringGrid->Height = (25 * NumPlayers) + 54;
23577  if(MultiplayerHostStringGrid->Height > MainScreen->Height - 100)
23578  {
23579  MultiplayerHostStringGrid->Height = MainScreen->Height - 120;
23580  }
23581  MultiplayerHostStringGrid->ColCount = 3;
23582  MultiplayerHostStringGrid->RowCount = NumPlayers + 2; //2 = heading & blank row
23583  MultiplayerHostStringGrid->ColWidths[1] = 128;
23584  MultiplayerHostStringGrid->Cells[0][0] = "Player";
23585  MultiplayerHostStringGrid->Cells[1][0] = "Railway";
23586  MultiplayerHostStringGrid->Cells[2][0] = "Ready?";
23587  bool RailwayFound = false;
23588  for(RLIt = RailwayList.begin(); RLIt != RailwayList.end(); RLIt++)
23589  {
23590  if(*RLIt != RailwayTitle) //host's railway
23591  {
23592  continue;
23593  }
23594  else
23595  {
23596  RailwayFound = true;
23597  break;
23598  }
23599  }
23600  if(!RailwayFound)
23601  {
23602  ShowMessage("Can't find '" + RailwayTitle + "' in coupling file - please load an appropriate railway and timetable or a pre-start session file");
23603  Utilities->CallLogPop(2349);
23604  return;
23605  }
23606  MultiplayerHostStringGrid->Visible = true;
23607  MPHPLoadCouplingFileButton->Enabled = false;
23608  MPHPGeneralLabel->Caption = "Awaiting player connections";
23609  int GridCount = 2; ;//row 1 is blank
23610  InfoVector.clear();
23611  TRlyUserInfo RlyUserInfo; //has default values
23612  unsigned char x = 1; //numbers start at 1
23613  //populate StringGrid & InfoVector with RailwayNames & numbers + "Host" as user in correct place
23614  for(RLIt = RailwayList.begin(); RLIt != RailwayList.end(); RLIt++)//railways in order
23615  {
23616  if(*RLIt == RailwayTitle) //host's railway
23617  {
23618  MultiplayerHostStringGrid->Cells[0][GridCount] = "Host";
23619  MultiplayerHostStringGrid->Cells[1][GridCount] = *RLIt; //RailwayName
23620  MultiplayerHostStringGrid->Cells[2][GridCount] = "Yes";
23621  RlyUserInfo.RailwayName = *RLIt; //RailwayName
23622  RlyUserInfo.UserName = "Host";
23623  RlyUserInfo.RlyUserNumber = x;
23624  InfoVector.push_back(RlyUserInfo);
23625  x++;
23626  }
23627  else
23628  {
23629  MultiplayerHostStringGrid->Cells[0][GridCount] = ""; //UserName
23630  MultiplayerHostStringGrid->Cells[1][GridCount] = *RLIt; //RailwayName
23631  MultiplayerHostStringGrid->Cells[2][GridCount] = "No";
23632  RlyUserInfo.RailwayName = *RLIt; //RailwayName
23633  RlyUserInfo.RlyUserNumber = x;
23634  InfoVector.push_back(RlyUserInfo);
23635  x++;
23636  }
23637  GridCount++;
23638  }
23639  CouplingFileLoadedFlag = true;
23640  MPHostClient->Active = true;
23641  }
23642  //no need for 'else' - messages given in called functions
23643  }
23644  Utilities->CallLogPop(2324);
23645  }
23646  catch(const EIdException &e) //non-error catch
23647  {
23648  ShowMessage("MPHPLoadCouplingFileButtonClick " + e.Message); //<--temporary
23649  Utilities->CallLogPop(2408);
23650  }
23651  catch(const Exception &e)
23652  {
23653  ErrorLog(225, e.Message);
23654  }
23655 }
23656 
23657 //---------------------------------------------------------------------------
23658 
23659 void __fastcall TInterface::MPHPCancelButtonClick(TObject *Sender)
23660 {
23661  try
23662  {
23663  TrainController->LogEvent("MPHPCancelButtonClick");
23664  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPHPCancelButtonClick");
23665  MPHostClient->Active = false;
23666  MPHPOwnIPEditBox->Text = "";
23667  MPHPOwnPortEditBox->Text = "";
23668  MultiplayerHostPanel->Visible = false;
23669  MultiplayerHostStringGrid->Visible = false;
23670  MPHPStartButton->Enabled = false;
23671 // AnsiCouplingMap.clear(); cleared in PopulateCouplingMap
23672  CouplingFileLoadedFlag = false;
23673  HostInSessionFlag = false;
23674  Utilities->CallLogPop(2350);
23675  }
23676  catch(const EIdException &e) //non-error catch
23677  {
23678  ShowMessage("MPHPCancelButtonClick " + e.Message); //<--temporary
23679  Utilities->CallLogPop(2409);
23680  }
23681  catch(const Exception &e)
23682  {
23683  ErrorLog(227, e.Message);
23684  }
23685 }
23686 
23687 //---------------------------------------------------------------------------
23688 
23689 void __fastcall TInterface::MPHPStartButtonClick(TObject *Sender)
23690 {
23691  try
23692  {
23693  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPHPStartButtonClick");
23694 
23695  ShowMessage("We're off!"); //<--temporary
23696  MultiplayerHostPanel->Visible = false;
23697  MultiplayerHostStringGrid->Visible = false;
23698  HostInSessionFlag = true;
23699  OperateButton->Click(); //start own session
23700  Utilities->CallLogPop(2369);
23701  }
23702  catch(const EIdException &e) //non-error catch
23703  {
23704  ShowMessage("MPHPStartButtonClick " + e.Message); //<--temporary
23705  Utilities->CallLogPop(2410);
23706  }
23707  catch(const Exception &e)
23708  {
23709  ErrorLog(237, e.Message);
23710  }
23711 }
23712 
23713 //---------------------------------------------------------------------------
23714 
23715 void __fastcall TInterface::MPHPOwnIPEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
23716 
23717 {
23718  try
23719  {
23720  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPHPOwnIPEditBoxKeyUp," + AnsiString(Key));
23721  if(Key == '\x0D') //CR
23722  {
23724  {
23725  ShowMessage("Format should be 'a.b.c.d' where a, b, c, and d are numbers between 0 and 255.\n\nObtain the address from the host and enter exactly as given.");
23726  MPHPOwnIPEditBox->Text = "";
23727  Utilities->CallLogPop(2351);
23728  return;
23729  }
23730  MPHPOwnIPEditBox->Enabled = false;
23731  if(MPHPOwnPortEditBox->Enabled == false)
23732  {
23733  MPHostClient->BoundIP = MPHPOwnIPEditBox->Text;
23734  MPHostClient->BoundPort = (unsigned short)MPHPOwnPortEditBox->Text.ToInt();
23735  MPHPLoadCouplingFileButton->Enabled = true;
23736  MPHPGeneralLabel->Caption = "Load coupling file";
23737  }
23738  }
23739  else
23740  {
23741  for(int x = 1; x <= MPHPOwnIPEditBox->Text.Length(); x++)
23742  {
23743  if((MPHPOwnIPEditBox->Text[x] != '.') && ((MPHPOwnIPEditBox->Text[x] < '0') || (MPHPOwnIPEditBox->Text[x] > '9')))
23744  {
23745  ShowMessage("Format should be 'a.b.c.d' where a, b, c, and d are numbers between 0 and 255.\n\nObtain the address from the host and enter exactly as given.");
23746  MPHPOwnIPEditBox->Text = "";
23747  Utilities->CallLogPop(2352);
23748  return;
23749  }
23750  }
23751  }
23752  Utilities->CallLogPop(2353);
23753  }
23754  catch(const EIdException &e) //non-error catch
23755  {
23756  ShowMessage("MPHPOwnIPEditBoxKeyUp " + e.Message); //<--temporary
23757  Utilities->CallLogPop(2411);
23758  }
23759  catch(const Exception &e)
23760  {
23761  ErrorLog(228, e.Message);
23762  }
23763 }
23764 //---------------------------------------------------------------------------
23765 
23766 void __fastcall TInterface::MPHPOwnPortEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
23767 
23768 {
23769  try
23770  {
23771  TrainController->LogEvent("MPHPOwnPortEditBoxKeyUp," + AnsiString(Key));
23772  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPHPOwnPortEditBoxKeyUp," + AnsiString(Key));
23773  if(Key == '\x0D') //CR
23774  {
23775  if((MPHPOwnPortEditBox->Text == "") || (MPHPOwnPortEditBox->Text.Length() < 5) || (MPHPOwnPortEditBox->Text.ToInt() < 49152) || (MPHPOwnPortEditBox->Text.ToInt() > 59999))
23776  {
23777  ShowMessage("Entry should be a number between 49152 and 59999.");
23778  MPHPOwnPortEditBox->Text = "";
23779  Utilities->CallLogPop(2354);
23780  return;
23781  }
23782  MPHPOwnPortEditBox->Enabled = false;
23783  if(MPHPOwnIPEditBox->Enabled == false)
23784  {
23785  MPHostClient->BoundIP = MPHPOwnIPEditBox->Text;
23786  MPHostClient->BoundPort = (unsigned short)MPHPOwnPortEditBox->Text.ToInt();
23787  MPHPLoadCouplingFileButton->Enabled = true;
23788  MPHPGeneralLabel->Caption = "Load coupling file";
23789  }
23790  }
23791  else
23792  {
23793  for(int x = 1; x <= MPHPOwnPortEditBox->Text.Length(); x++)
23794  {
23795  if((MPHPOwnPortEditBox->Text[x] < '0') || (MPHPOwnPortEditBox->Text[x] > '9'))
23796  {
23797  ShowMessage("Entry should be a number between 49152 and 59999.");
23798  MPHPOwnPortEditBox->Text = "";
23799  Utilities->CallLogPop(2355);
23800  return;
23801  }
23802  }
23803  }
23804  Utilities->CallLogPop(2356);
23805  }
23806  catch(const EIdException &e) //non-error catch
23807  {
23808  ShowMessage("MPHPOwnPortEditBoxKeyUp " + e.Message); // <--temporary
23809  Utilities->CallLogPop(2412);
23810  }
23811  catch(const Exception &e)
23812  {
23813  ErrorLog(229, e.Message);
23814  }
23815 }
23816 
23817 //---------------------------------------------------------------------------
23818 
23819 void __fastcall TInterface::IPCheckLinkLabelLinkClick(TObject *Sender, const UnicodeString Link,
23820  TSysLinkType LinkType)
23821 {
23822  if(LinkType == sltURL)
23823  {
23824  ::ShellExecute(Handle, NULL, Link.c_str(), NULL, NULL, SW_SHOWNORMAL);
23825  }
23826 }
23827 
23828 //---------------------------------------------------------------------------
23829 
23831 {
23832  if(lower.first < higher.first) //RailwayName
23833  {
23834  return(true);
23835  }
23836  else if(lower.first > higher.first)
23837  {
23838  return(false);
23839  }
23840  else if(lower.second.first < higher.second.first) //railway names same, lower H < higher H
23841  {
23842  return(true);
23843  }
23844  else if(lower.second.first > higher.second.first) //railway names same, lower H > Higher H
23845  {
23846  return(false);
23847  }
23848  else if(lower.second.second < higher.second.second) //railway names same, H values same, lower V < higher V
23849  {
23850  return(true);
23851  }
23852  else return(false); //railway names same, H values same, lower V > higher V or both V values same
23853  //both H & V values shouldn't be same for same railway but if for some reason they are then
23854  //the map will reject one of them as both comp(a, b) and comp(b, a) are false
23855 }
23856 
23857 // ---------------------------------------------------------------------------
23858 
23859 bool TInterface::TDynamicMapComp:: operator()(const TNumHVPair& lower, const TNumHVPair& higher) const
23860 {
23861  if(lower.first < higher.first) //compare numbers
23862  {
23863  return(true);
23864  }
23865  else if(lower.first > higher.first)
23866  {
23867  return(false);
23868  }
23869  else if(lower.second.first < higher.second.first) //number values same (same railway/user), compare H values
23870  {
23871  return(true);
23872  }
23873  else if(lower.second.first > higher.second.first)
23874  {
23875  return(false);
23876  }
23877  else if(lower.second.second < higher.second.second) //number & H values same, compare V values
23878  {
23879  return(true);
23880  }
23881  else if(lower.second.second > higher.second.second)
23882  {
23883  return(false);
23884  }
23885  else return(false); //number + H & V values same, shouldn't be same for same railway but if for some reason they are then
23886  //the map will reject one of them as both comp(a, b) and comp(b, a) are false
23887 }
23888 
23889 // ---------------------------------------------------------------------------
23890 
23891 bool TInterface::PopulateCouplingMap(AnsiString FileName, int &NumExt)
23892 // read file CouplingMap.csv (in same directory as railway.exe) and build AnsiCouplingMap (based on railway name), AllRailwaysCouplingMap (based on
23893 //RlyUserNumber) & HostCombinedDynamicMap. The maps have two sets of couplings so each railway/HVpair is a key
23894 {
23895  TrainController->LogEvent("PopulateCouplingMap");
23896  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateCouplingMap,FileName," + FileName); //no caller as only called once
23897  AnsiString RailwayName1 = "", RailwayName2 = "", OneLine = "", ExitID1 = "", ExitID2 = "";
23898  int HLoc1, HLoc2, VLoc1, VLoc2, CPos, NumRailways;
23899  TAnsiCouplingPair AnsiCouplingPair1, AnsiCouplingPair2;
23900  TAnsiCouplingMapEntry AnsiCouplingMapEntry;
23901  AnsiCouplingMap.clear();
23902  THVShortPair HVExitPair1, HVExitPair2;
23903  std::ifstream TxtFile(FileName.c_str()); //railway1, HLoc, VLoc, railway2, HLoc, VLoc CRLF repeated
23904  AnsiString SyntaxError = "Coupling file error - structure should consist of lines of 'R1; exit1ID; R2; exit2ID' and so on "
23905  "for all coupled exits, where R1 and R2 are railway names without the '.rly' extension, exit1ID is an "
23906  "exit ID in R1, and exit2ID is an exit ID in R2";
23907  if(TxtFile.fail())
23908  {
23909  ShowMessage("Can't find the coupling file. Please make sure it's located in the directory selected and has a .txt extension");
23910  Utilities->CallLogPop(2325);
23911  return(false);
23912  }
23913  while(!TxtFile.eof())
23914  {
23915  if(!Utilities->ReadOneLineFromCouplingFile(TxtFile, OneLine))
23916  {
23917  ShowMessage(SyntaxError);
23918  TxtFile.close();
23919  Utilities->CallLogPop(2326);
23920  return(false);
23921  }
23922  if(TxtFile.eof() && (OneLine == ""))
23923  {
23924  break;
23925  }
23926  if(OneLine.AnsiPos(',') != 0)
23927  {
23928  ShowMessage(SyntaxError);
23929  TxtFile.close();
23930  Utilities->CallLogPop(2327);
23931  return(false);
23932  }
23933  TrainController->StripSpaces(6, OneLine);
23934  // strip both leading and trailing spaces at ends of line and spaces before and after all commas (and semicolons) within the line
23935  if(OneLine != "")
23936  {
23937  int DelimPos = OneLine.Pos(';');
23938  if(DelimPos < 2) //0 = can't find, 1 = first character is a comma - both errors
23939  {
23940  ShowMessage(SyntaxError);
23941  TxtFile.close();
23942  Utilities->CallLogPop(2328);
23943  return(false);
23944  }
23945  else
23946  {
23947  RailwayName1 = OneLine.SubString(1, (DelimPos - 1));
23948  OneLine = OneLine.SubString(DelimPos + 1, OneLine.Length() - DelimPos); //OneLine is now the remainder
23949  if(RailwayName1.LowerCase().SubString(RailwayName1.Length() - 3, 4) == ".rly")
23950  {
23951  RailwayName1 = RailwayName1.SubString(1, RailwayName1.Length() - 4); //ignore .rly if present
23952  }
23953  }
23954  DelimPos = OneLine.Pos(';');
23955  if(DelimPos < 2) //0 = can't find, 1 = first character is a comma - both errors
23956  {
23957  ShowMessage(SyntaxError);
23958  TxtFile.close();
23959  Utilities->CallLogPop(2329);
23960  return(false);
23961  }
23962  else
23963  {
23964  ExitID1 = OneLine.SubString(1, (DelimPos - 1));
23965  OneLine = OneLine.SubString(DelimPos + 1, OneLine.Length() - DelimPos); //OneLine is now the remainder
23966  if(!ConvertIDToPair(ExitID1, HVExitPair1))
23967  {
23968  TxtFile.close();
23969  Utilities->CallLogPop(2330);
23970  return(false);
23971  }
23972  }
23973  DelimPos = OneLine.Pos(';');
23974  if(DelimPos < 2) //0 = can't find, 1 = first character is a comma - both errors
23975  {
23976  ShowMessage(SyntaxError);
23977  TxtFile.close();
23978  Utilities->CallLogPop(2331);
23979  return(false);
23980  }
23981  else
23982  {
23983  RailwayName2 = OneLine.SubString(1, (DelimPos - 1));
23984  OneLine = OneLine.SubString(DelimPos + 1, OneLine.Length() - DelimPos); //OneLine is now the remainder
23985  if(RailwayName2.LowerCase().SubString(RailwayName2.Length() - 3, 4) == ".rly")
23986  {
23987  RailwayName2 = RailwayName2.SubString(1, RailwayName2.Length() - 4); //ignore .rly if present
23988  }
23989  }
23990  if(OneLine == "") //should now only contain Exit2ID
23991  {
23992  ShowMessage(SyntaxError);
23993  TxtFile.close();
23994  Utilities->CallLogPop(2332);
23995  return(false);
23996  }
23997  else
23998  {
23999  ExitID2 = OneLine;
24000  if(!ConvertIDToPair(ExitID2, HVExitPair2))
24001  {
24002  TxtFile.close();
24003  Utilities->CallLogPop(2333);
24004  return(false);
24005  }
24006  }
24007  AnsiCouplingPair1.first = RailwayName1;
24008  AnsiCouplingPair1.second = HVExitPair1;
24009  AnsiCouplingPair2.first = RailwayName2;
24010  AnsiCouplingPair2.second = HVExitPair2;
24011  AnsiCouplingMapEntry.first = AnsiCouplingPair1;
24012  AnsiCouplingMapEntry.second = AnsiCouplingPair2;
24013  AnsiCouplingMap.insert(AnsiCouplingMapEntry);
24014  AnsiCouplingMapEntry.first = AnsiCouplingPair2; //add entry for reversed pairs
24015  AnsiCouplingMapEntry.second = AnsiCouplingPair1;
24016  AnsiCouplingMap.insert(AnsiCouplingMapEntry);
24017  RailwayList.push_back(RailwayName1);
24018  RailwayList.push_back(RailwayName2);
24019  }
24020  else
24021  {
24022  continue; //ignore blank lines
24023  }
24024  }
24025  TxtFile.close();
24026  RailwayList.sort();
24027  RailwayList.unique(); //remove duplicates
24028  NumPlayers = RailwayList.size();
24029 //now convert to number based coupling map
24030  AllRailwaysCouplingMap.clear();
24031  TNumHVPair NumHVPair1, NumHVPair2;
24032  for(TAnsiCouplingMap::iterator ACMIt = AnsiCouplingMap.begin(); ACMIt != AnsiCouplingMap.end(); ACMIt++)
24033  {
24034  int ListCounter = 1; //RlyUserNumbers start at 1
24035  for(RLIt = RailwayList.begin(); RLIt != RailwayList.end(); RLIt++)
24036  {
24037  if(ACMIt->first.first == *RLIt)
24038  {
24039  NumHVPair1.first = ListCounter;
24040  NumHVPair1.second = ACMIt->first.second;
24041  break;
24042  }
24043  ListCounter++;
24044  }
24045  ListCounter = 1;
24046  for(RLIt = RailwayList.begin(); RLIt != RailwayList.end(); RLIt++)
24047  {
24048  if(ACMIt->second.first == *RLIt)
24049  {
24050  NumHVPair2.first = ListCounter;
24051  NumHVPair2.second = ACMIt->second.second;
24052  break;
24053  }
24054  ListCounter++;
24055  }
24056  AllRailwaysCouplingPair.first = NumHVPair1;
24057  AllRailwaysCouplingPair.second = NumHVPair2;
24058  AllRailwaysCouplingMap.insert(AllRailwaysCouplingPair); //includes reversed couplings
24059  }
24060 //now build the HostCombinedDynamicMap without any service info
24061  HostCombinedDynamicMap.clear();
24062  TDynamicMapEntry DMEntry;
24063  TServiceInfo ServiceInfo; //default values
24064  for(TCMIterator CMIt = AllRailwaysCouplingMap.begin(); CMIt != AllRailwaysCouplingMap.end(); CMIt++)
24065  {
24066  DMEntry.first = CMIt->first;
24067  DMEntry.second = ServiceInfo;
24068  HostCombinedDynamicMap.insert(DMEntry); //includes reversed couplings
24069  }
24070  ShowMessage("File loaded successfully");
24071  Utilities->CallLogPop(2334);
24072  return(true);
24073 }
24074 
24075 // ---------------------------------------------------------------------------
24076 
24077 bool TInterface::ConvertIDToPair(AnsiString HVID, THVShortPair &HVPair) //true for ok
24078 {
24079  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConvertIDToPair," + HVID); //no caller as only called twice & HVID identifies
24080  AnsiString HString = "", VString = "";
24081  if(HVID == "") //should be covered in calling function but include anyway
24082  {
24083  ShowMessage("Coupling file error - an exit ID is missing from the file");
24084  Utilities->CallLogPop(2335);
24085  return(false);
24086  }
24087  for(int x = 1; x <= HVID.Length(); x++)
24088  {
24089  char C = HVID[x];
24090  if(((C < '0') || (C > '9')) && (C != 'N') && (C != '-'))
24091  {
24092  ShowMessage("Coupling file error - an exit ID contains illegal characters, can only include digits, '-' or 'N'");
24093  Utilities->CallLogPop(2336);
24094  return(false);
24095  }
24096  }
24097  int DashPos = HVID.Pos('-');
24098  if(DashPos == 0)
24099  {
24100  ShowMessage("Coupling file error - structure should consist of lines of 'R1, exit1 ID, R2, corresponding exit ID' and so on "
24101  "for all coupled exits, where R1 and R2 are railway names without the '.rly' extension");
24102  Utilities->CallLogPop(2337);
24103  return(false);
24104  }
24105  else
24106  {
24107  HString = HVID.SubString(1, DashPos - 1);
24108  VString = HVID.SubString(DashPos + 1, HVID.Length() - DashPos);
24109  if(HString[1] == 'N')
24110  {
24111  HString = HString.SubString(2, HString.Length() - 1);
24112  HVPair.first = -HString.ToInt();
24113  }
24114  else
24115  {
24116  HVPair.first = HString.ToInt();
24117  }
24118  if(VString[1] == 'N')
24119  {
24120  VString = VString.SubString(2, VString.Length() - 1);
24121  HVPair.second = -VString.ToInt();
24122  }
24123  else
24124  {
24125  HVPair.second = VString.ToInt();
24126  }
24127  }
24128  Utilities->CallLogPop(2338);
24129  return(true);
24130 }
24131 
24132 // ---------------------------------------------------------------------------
24133 
24134 bool TInterface::MultiplayerRailwayValid(AnsiString RailwayName, char &ErrorNumber)
24135 {
24136  Utilities->CallLog.push_back(Utilities->TimeStamp() + "MultiplayerRailwayValid");
24137  ErrorNumber = 0; //no error
24138  bool Listed = false, Available = false, RetType = false;
24139  for(int x = 2; x < NumPlayers + 2; x++)
24140  {
24141  if(RailwayName == MultiplayerHostStringGrid->Cells[1][x])
24142  {
24143  Listed = true;
24144  if(MultiplayerHostStringGrid->Cells[0][x] == "")
24145  {
24146  Available = true;
24147  }
24148  break;
24149  }
24150  }
24151  if(!Listed)
24152  {
24153  ErrorNumber = 1;
24154  }
24155  else if(!Available)
24156  {
24157  ErrorNumber = 2;
24158  }
24159  else
24160  {
24161  RetType = true;
24162  }
24163  Utilities->CallLogPop(2357);
24164  return(RetType);
24165 }
24166 
24167 //---------------------------------------------------------------------------
24168 
24169 short TInterface::BuildOneRailwayCouplingMap(unsigned char PlayerNumber)
24170 {
24171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "BuildOneRailwayCouplingMap");
24172  OneRailwayCouplingMap.clear();
24173  TCouplingMap::iterator CMIt;
24174  short Count = 0;
24175  for(CMIt = AllRailwaysCouplingMap.begin(); CMIt != AllRailwaysCouplingMap.end(); CMIt++)
24176  {
24177  if(CMIt->first.first == PlayerNumber)
24178  {
24179  OneRailwayCouplingPair.first = CMIt->first; //own player number + H & V for own railway
24180  OneRailwayCouplingPair.second = CMIt->second; //other player number & coupled H&V
24182  Count++;
24183  }
24184  }
24185  Utilities->CallLogPop(2378);
24186  return(Count * 10); //this is the number of bytes to be entered into a datagram (apart from marker & username if they are required)
24187 }
24188 
24189 //---------------------------------------------------------------------------
24190 
24192 { //host read & respond new for multiplayer - every cycle
24193  try
24194  {
24195  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HostHandshakingActions");
24197  {
24198  EIdExceptionSource += " CouplingFileLoadedAwaitingPlayers";
24199  UnicodeString Data = "";
24200  UnicodeString PeerIP = "";
24201  unsigned short PeerPort = 0;
24202  unsigned char marker;
24203  bool Found1 = false, Found2 = false;
24204  AnsiString PlayerRailwayName, PlayerUserName;
24205  char ErrorNumber; //indicates type of error 0 = ok, 1 = not listed, 2 = already taken
24206  UnicodeString Message1 = "The railway doesn't appear in the coupled group - the host can advise which railways are valid";
24207  UnicodeString Message2 = "The railway has already been allocated - the host can advise which are still available";
24208  TBytes HostBuffer;
24209  HostBuffer.Length = 8192; //have to set long enough initially, will reduce later
24210  HostBuffer.Length = MPHostClient->ReceiveBuffer(HostBuffer, PeerIP, PeerPort, 10);
24211  //will be of form 'marker' then UserName ';' RailwayName (marker is '1' for first contact, '2' for ready to begin, no space or delimieter before railway name)
24212  MPHostClient->Active = false; //don't receive any messages until have dealt with this
24213  if(HostBuffer.Length != 0)
24214  {
24215  if(HostBuffer[0] == '1') //player first contact, no binary content
24216  {
24217  //check validity
24218  bool FoundFlag = false;
24219  for(int x = 1; x < HostBuffer.Length; x++)
24220  {
24221  if((HostBuffer[x] == ';') && (x > 1) && (x < (HostBuffer.Length - 1))) // ';' present and not first ot last character
24222  {
24223  FoundFlag = true;
24224  break;
24225  }
24226  }
24227  if(!FoundFlag)
24228  {
24229  Utilities->CallLogPop(2387); //skip this loop
24230  return;
24231  }
24232  for(int x = 1; x < HostBuffer.Length; x++)
24233  {
24234  if((HostBuffer[x] < ' ') || (HostBuffer[x] > '~'))
24235  {
24236  MPHostClient->Active = true;
24237  Utilities->CallLogPop(2371); //skip this loop
24238  return;
24239  }
24240  }
24241  Data = BytesToString(HostBuffer);
24242  int DelimPos = Data.Pos(';');
24243  PlayerUserName = Data.SubString(2, DelimPos - 2);
24244  PlayerRailwayName = Data.SubString(DelimPos + 1, Data.Length() - DelimPos);
24245  unsigned char PlayerNumber;
24246  if(!RlyToNum(PlayerRailwayName, PlayerNumber))
24247  {
24248  ShowMessage("Error in converting incoming information for player '" + PlayerUserName + "', ask player to cancel and join again");
24249  RemovePlayerFromStringGridAndInfoVector(0, PlayerUserName);
24250  MPHostClient->Active = true;
24251  Utilities->CallLogPop(2372); //skip this loop
24252  return;
24253  }
24254  if(MultiplayerRailwayValid(PlayerRailwayName, ErrorNumber))
24255  {
24256  //host can accept or reject
24257  UnicodeString RejectString = PlayerUserName + " is asking to join with railway " + PlayerRailwayName + ". OK to join?";
24258  int button = Application->MessageBox(RejectString.c_str(), L"Request", MB_YESNO);
24259  if(button == IDNO)
24260  {
24261  MPHostClient->SendBuffer(PeerIP, PeerPort, ToBytes("The host did not accept your request to join"));
24262  MPHostClient->Active = false; //keep it false (send sets it to true)
24263  }
24264  else
24265  {
24266  //find correct slot in MultiplayerHostStringGrid & InfoVector & add username
24267  for(int x = 0; x < NumPlayers; x++)
24268  {
24269  if(MultiplayerHostStringGrid->Cells[1][x + 2] == PlayerRailwayName)
24270  {
24271  MultiplayerHostStringGrid->Cells[0][x + 2] = PlayerUserName;
24272  Found1 = true;
24273  break;
24274  }
24275  }
24276  for(int x = 0; x < NumPlayers; x++)
24277  {
24278  if(InfoVector.at(x).RailwayName == PlayerRailwayName) //already have number
24279  {
24280  InfoVector.at(x).UserName = PlayerUserName;
24281  InfoVector.at(x).UserIP = PeerIP;
24282  InfoVector.at(x).UserPort = PeerPort;
24283  Found2 = true;
24284  break;
24285  }
24286  }
24287  if(!Found1 || !Found2)
24288  {
24289  //error, should find both
24290  ShowMessage("Error in initial contact information for player '" + PlayerUserName + "', ask player to cancel and join again");
24291  RemovePlayerFromStringGridAndInfoVector(1, PlayerUserName);
24292  MPHostClient->Active = true;
24293  Utilities->CallLogPop(2373); //skip this loop
24294  return;
24295  }
24296 // now send OwnRlyUserNumber + shortHVs then coupled number + short HVs (10 bytes total per exit/entry), no separators
24297  short NumBytes = BuildOneRailwayCouplingMap(PlayerNumber);
24298  TCouplingMap::iterator CMIt = OneRailwayCouplingMap.begin();
24299  TBytes HVbuffer;
24300  HVbuffer.Length = NumBytes;
24301  for(int x = 0; x < NumBytes; x += 10)
24302  {
24303  HVbuffer[x] = CMIt->first.first; // = player's OwnRlyUserNumber
24304  HVbuffer[x + 1] = CMIt->first.second.first & 0x00FF; //H low then high
24305  HVbuffer[x + 2] = (CMIt->first.second.first & 0xFF00) / 256;
24306  HVbuffer[x + 3] = CMIt->first.second.second & 0x00FF; //V low then high
24307  HVbuffer[x + 4] = (CMIt->first.second.second & 0xFF00) / 256;
24308 
24309  HVbuffer[x + 5] = CMIt->second.first; //coupled railway usernumber
24310  HVbuffer[x + 6] = CMIt->second.second.first & 0x00FF; //H low then high
24311  HVbuffer[x + 7] = (CMIt->second.second.first & 0xFF00) / 256;
24312  HVbuffer[x + 8] = CMIt->second.second.second & 0x00FF; //V low then high
24313  HVbuffer[x + 9] = (CMIt->second.second.second & 0xFF00) / 256;
24314  CMIt++;
24315  }
24316  MPHostClient->SendBuffer(PeerIP, PeerPort, HVbuffer);
24317  MPHostClient->Active = false; //keep it false
24318  }
24319  }
24320  else
24321  {
24322  //send message that not listed (1) or already taken (2) - cancel panel and load a valid railway (ask host which ok)
24323  //send it outside the data receipt as data won't keep being sent from player
24324  if(ErrorNumber == 1)
24325  {
24326  MPHostClient->SendBuffer(PeerIP, PeerPort, ToBytes(Message1));
24327  }
24328  else if(ErrorNumber == 2)
24329  {
24330  MPHostClient->SendBuffer(PeerIP, PeerPort, ToBytes(Message2));
24331  }
24332  MPHostClient->Active = false; //keep it false (send sets it to true)
24333  }
24334  }
24335  else if(HostBuffer[0] == '2') //player second contact, marker = 2, username, then DynMapToHost in buffer form
24336  {
24337  TDynamicMap::iterator DMIt, HMIt;
24338  if(BuildDynamicMapFromPlayerDatagram(0, DynMapToHost, HostBuffer, marker, PlayerUserName)) //this performs validity checks
24339  {
24340 // update HostCombinedDynamicMap. Won't alter anything here as no service information, but acts as a check that can find all elements
24341  for(DMIt = DynMapToHost.begin(); DMIt != DynMapToHost.end(); DMIt++) //unlikely to be in alphabetical order
24342  {
24343  HMIt = HostCombinedDynamicMap.find(DMIt->first); //should always find it
24344  if(HMIt != HostCombinedDynamicMap.end())
24345  {
24346  HMIt->second = DMIt->second;
24347  }
24348  else
24349  {
24350  ShowMessage("Failed to locate player information in host database for player '" + PlayerUserName + "', ask player to cancel and join again");
24351  RemovePlayerFromStringGridAndInfoVector(2, PlayerUserName);
24352  Utilities->CallLogPop(2374); //skip this loop
24353  return;
24354  }
24355  }
24356  }
24357  else
24358  {
24359  Utilities->CallLogPop(2375); //skip this loop
24360  return;
24361  }
24362  //update StringGrid & InfoVector
24363  Found1 = false;
24364  Found2 = false;
24365  for(int x = 0; x < NumPlayers; x++)
24366  {
24367  if(MultiplayerHostStringGrid->Cells[0][x + 2] == PlayerUserName)
24368  {
24369  MultiplayerHostStringGrid->Cells[2][x + 2] = "Yes";
24370  Found1 = true;
24371  }
24372  }
24373  for(int x = 0; x < NumPlayers; x++)
24374  {
24375  if(InfoVector.at(x).UserName == PlayerUserName) //already have number
24376  {
24377  InfoVector.at(x).UserIP = PeerIP;
24378  InfoVector.at(x).UserPort = PeerPort;
24379  Found2 = true;
24380  }
24381  }
24382  if(!Found1 || !Found2)
24383  {
24384  //error, should find both
24385  ShowMessage("Error in 'ready to begin' contact information for player '" + PlayerUserName + "', ask player to cancel and join again");
24386  RemovePlayerFromStringGridAndInfoVector(3, PlayerUserName);
24387  Utilities->CallLogPop(2388); //skip this loop
24388  return;
24389  }
24390 // now send return message to player
24391  TBytes HVbuffer;
24392  HVbuffer.Length = 22;
24393  UnicodeString Message = "Await simulation start";
24394  HVbuffer = ToBytes(Message);
24395  MPHostClient->SendBuffer(PeerIP, PeerPort, HVbuffer);
24396  MPHostClient->Active = false; //keep it false (send sets it to true)
24397 //check if all players ready to start, and if so enable the 'start session' button
24398  bool AllReady = true;
24399  for(int x = 0; x < NumPlayers; x++)
24400  {
24401  if(MultiplayerHostStringGrid->Cells[2][x + 2] != UnicodeString("Yes"))
24402  {
24403  AllReady = false;
24404  }
24405  }
24406  if(AllReady)
24407  {
24408  MPHPStartButton->Enabled = true;
24409  }
24410  }
24411  else if(HostBuffer[0] == '3') //player clicked cancel button
24412  {
24413  for(int x = 1; x < HostBuffer.Length; x++) //validity check
24414  {
24415  if((HostBuffer[x] < ' ') || (HostBuffer[x] > '~'))
24416  {
24417  Utilities->CallLogPop(2392); //skip this loop
24418  return;
24419  }
24420  }
24421  Data = BytesToString(HostBuffer); //message is '3' then username and nothing else
24422  PlayerUserName = Data.SubString(2, Data.Length() - 1);
24423  TBytes HVbuffer;
24424  HVbuffer.Length = 9;
24425  UnicodeString Message = "Cancelled";
24426  HVbuffer = ToBytes(Message);
24427  MPHostClient->SendBuffer(PeerIP, PeerPort, HVbuffer); //send response each time received but only show message etc. once
24428  MPHostClient->Active = false; //keep it false (send sets it to true)
24429  unsigned char RlyUserNumber;
24430  if(!UserToNum(PlayerUserName, RlyUserNumber)) //use this to check if already removed from vector
24431  {
24432  Utilities->CallLogPop(2391); //already removed from infovector so go no further
24433  return;
24434  }
24435  else
24436  {
24437  ShowMessage("Player '" + PlayerUserName + "', has cancelled the join request");
24438  RemovePlayerFromStringGridAndInfoVector(4, PlayerUserName);
24439  Utilities->CallLogPop(2389);
24440  return;
24441  }
24442  }
24443  else if(HostBuffer[0] == '4') //player awaiting start
24444  {
24445  if(HostInSessionFlag)
24446  {
24447  for(int x = 1; x < HostBuffer.Length; x++) //validity check
24448  {
24449  if((HostBuffer[x] < ' ') || (HostBuffer[x] > '~'))
24450  {
24451  Utilities->CallLogPop(2393); //skip this loop
24452  return;
24453  }
24454  }
24455  Data = BytesToString(HostBuffer); //message is '3' then username and nothing else
24456  PlayerUserName = Data.SubString(2, Data.Length() - 1);
24457  TBytes HVbuffer;
24458  HVbuffer.Length = 13;
24459  UnicodeString Message = "Start Session";
24460  HVbuffer = ToBytes(Message);
24461  MPHostClient->SendBuffer(PeerIP, PeerPort, HVbuffer); //send response each time received, eventually all players will start
24462  //when players are in session they just message every 5 secs & get TTClock in response
24463  MPHostClient->Active = false; //keep it false (send sets it to true)
24464  }
24465  //else ignore
24466  }
24467  else if(HostBuffer[0] == '5') //in session
24468  {
24469  TDynamicMap::iterator DMIt, HMIt;
24470  if(BuildDynamicMapFromPlayerDatagram(1, DynMapToHost, HostBuffer, marker, PlayerUserName)) //this performs validity checks
24471  {
24472 // update HostCombinedDynamicMap
24473  for(DMIt = DynMapToHost.begin(); DMIt != DynMapToHost.end(); DMIt++) //unlikely to be in alphabetical order
24474  {
24475  HMIt = HostCombinedDynamicMap.find(DMIt->first); //should always find it
24476  if(HMIt != HostCombinedDynamicMap.end()) //if not skip
24477  {
24478  HMIt->second = DMIt->second;
24479  }
24480  }
24481  }
24482  //construct DynMapFromHost & send as buffer along with TTClockTime, then at player end receive it and update TTClock etc
24483  unsigned char RlyUserNumber;
24484  if(!UserToNum(PlayerUserName, RlyUserNumber)) //get number from InfoVector
24485  {
24486  Utilities->CallLogPop(2395); //skip this loop
24487  return;
24488  }
24489  DynMapFromHost.clear();
24490  bool LoadingFlag = false;
24491  HMIt = HostCombinedDynamicMap.begin();
24492  while(HMIt != HostCombinedDynamicMap.end())
24493  {
24494  if(HMIt->first.first == RlyUserNumber)
24495  {
24496  DynMapFromHost.insert(*HMIt);
24497  LoadingFlag = true;
24498  }
24499  if(LoadingFlag && (HMIt->first.first != RlyUserNumber))
24500  {
24501  break; //no point looking after last insert
24502  }
24503  HMIt++;
24504  }
24505  TBytes HVbuffer;
24506  HVbuffer.Length = 8192;
24507  BuildDatagramFromHostMap(0, HVbuffer, DynMapFromHost); //length set at end of this function, this includes TTClockTime as 32 bit integer
24508  MPHostClient->SendBuffer(PeerIP, PeerPort, HVbuffer);
24509  MPHostClient->Active = false; //keep it false (send sets it to true)
24510  }
24511 
24512  //if hostbuffer[0] outside accepted range ignore
24513  }
24514  else
24515  {
24516  //nothing to read or error in datagram format - if error ignore & read next time it's sent
24517  }
24518  }
24519  MPHostClient->Active = true;
24520  Utilities->CallLogPop(2415);
24521  }
24522  catch(const EIdException &e) //non-error catch
24523 //if no response from peer then get a 'connection reset by peer' message which isn't valid
24524  {
24525  Utilities->CallLogPop(2414);
24526  }
24527  catch(const Exception &e)
24528  {
24529  ErrorLog(239, e.Message);
24530  }
24531 }
24532 
24533 //---------------------------------------------------------------------------
24534 //player functions
24535 //---------------------------------------------------------------------------
24536 
24537 
24538 void __fastcall TInterface::JoinMultiplayerSessionMenuItemClick(TObject *Sender) //player first action
24539 {
24540  try
24541  {
24542  TrainController->LogEvent("JoinMultiplayerSessionMenuItemClick");
24543  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinMultiplayerSessionMenuItemClick");
24544  MultiplayerPlayerPanel->Visible = true;
24545  MultiplayerPlayerPanel->Left = MainScreen->Left + (MainScreen->Width / 2) - (MultiplayerPlayerPanel->Width / 2);
24546  MultiplayerPlayerPanel->Top = MainScreen->Top + 100;
24547  MPPlayerClient->Active = false;
24548  MPCPLabel2->Caption = "Complete the boxes and press 'Enter' for each."; //top box
24549  MPCPLabel4->Caption = "Joining request not yet sent"; //opp image
24550  MPCPLabel7->Caption = "Only click 'Send' when the host is ready - the host will"; //lower box top
24551  MPCPLabel8->Caption = "advise by communicating outside the game."; //lower box bottom
24552  MPCPLabel5->Caption = "Host IP address (obtain from host)";
24553  MPCPLabel6->Caption = "Host port number (obtain from host)";
24554  MPCPLabel3->Caption = "Player name (2 to 4 characters)";
24555 
24556  MultiplayerHostSessionMenuItem->Enabled = false;
24557  SaveMultiplayerSessionMenuItem->Enabled = false;
24558  EndSimulationMenuItem->Enabled = false;
24559  ShowHideStringGridMenuItem->Enabled = false;
24560  JoinMultiplayerSessionMenuItem->Enabled = false;
24561  ExitSimulationMenuItem->Enabled = false;
24562  HostInSessionFlag = false;
24563  CouplingFileLoadedFlag = false;
24565  PlayerReadyToBeginFlag = false;
24566  PlayerCancelJoinFlag = false;
24568  PlayerInSessionFlag = false;
24569 
24570  MPCPHostIPEditBox->Visible = true;
24571  MPCPHostPortEditBox->Visible = true;
24572  MPCPPlayerNameEditBox->Visible = true;
24573  MPCPHostImage->Visible = true;
24574  MPCPHostImage->Picture->Assign(RailGraphics->SolidCircleRed);
24575  MPCPSendButton->Enabled = false;
24576  MPCPReadyToBeginButton->Enabled = false;
24577  MPCPPlayerNameEditBox->Enabled = true;
24578  MPCPHostPortEditBox->Enabled = true;
24579  MPCPHostIPEditBox->Enabled = true;
24580  MPCPPlayerNameEditBox->Text = "AB"; // <--temporary - change to "" for release
24581  MPCPHostPortEditBox->Text = "50000";// <--temporary - change to "" for release
24582  MPCPHostIPEditBox->Text = "127.0.0.1";// <--temporary - change to "" for release
24583  Utilities->CallLogPop(2358);
24584  }
24585 
24586  catch(const Exception &e)
24587  {
24588  ErrorLog(230, e.Message);
24589  }
24590 }
24591 
24592 //---------------------------------------------------------------------------
24593 
24594 void __fastcall TInterface::MPCPSendButtonClick(TObject *Sender)
24595 {
24596  try
24597  {
24598  TrainController->LogEvent("MPCPSendButtonClick");
24599  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPCPSendButtonClick");
24600  MPCPLabel2->Caption = "Await host response then click 'Ready to begin'";
24601  MPCPLabel4->Caption = "Awaiting host response";
24602  MPCPLabel7->Caption = "";
24603  MPCPLabel8->Caption = "";
24604  MPCPHostImage->Picture->Assign(RailGraphics->SolidCircleYellow);
24605  MPCPSendButton->Enabled = false;
24607  P5SCounter = 0; //temporary
24608 
24609 
24610 //send message every 10 seconds and listen for response
24611 //when response received give 'received message', give greem light, and 'click ready to bein' message
24612 
24613 
24614  Utilities->CallLogPop(2359);
24615  }
24616 
24617  catch(const Exception &e)
24618  {
24619  ErrorLog(231, e.Message);
24620  }
24621 }
24622 
24623 //---------------------------------------------------------------------------
24624 
24625 void __fastcall TInterface::MPCPCancelButtonClick(TObject *Sender)
24626 {
24627  try
24628  {
24629  TrainController->LogEvent("MPCPCancelButtonClick");
24630  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPCPCancelButtonClick");
24631  MPCPSendButton->Enabled = false;
24632  MPCPReadyToBeginButton->Enabled = false;
24633  MPCPPlayerNameEditBox->Text = "";
24634  MPCPHostPortEditBox->Text = "";
24635  MPCPHostIPEditBox->Text = "";
24636  MultiplayerPlayerPanel->Visible = false;
24638  PlayerReadyToBeginFlag = false;
24640  PlayerInSessionFlag = false;
24641  PlayerCancelJoinFlag = true;
24642  Track->MultiplayerOverlayMap.clear();
24644  Utilities->CallLogPop(2341);
24645  }
24646 
24647  catch(const Exception &e)
24648  {
24649  ErrorLog(236, e.Message);
24650  }
24651 }
24652 
24653 //---------------------------------------------------------------------------
24654 
24655 void __fastcall TInterface::MPCPReadyToBeginButtonClick(TObject *Sender)
24656 {
24657  try
24658  {
24659  TrainController->LogEvent("MPCPReadyToBeginButtonClick");
24660  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPCPReadyToBeginButtonClick");
24661  int button = Application->MessageBox(L"This will transfer all timer controls to the host.\n\n Click 'Yes' to wait for the host to start the simulation.\n\nOK to proceed?", L"Warning!", MB_YESNO | MB_ICONWARNING);
24662  if(button == IDNO)
24663  {
24664  Utilities->CallLogPop(2339);
24665  return;
24666  }
24667 //transfer control etc
24668  PlayerReadyToBeginFlag = true;
24669 //allow certain buttons but not timer controls
24670  CallingOnButton->Enabled = true;
24671  PresetAutoSigRoutesButton->Enabled = true;
24672  AutoSigsButton->Enabled = true;
24673  SigPrefConsecButton->Enabled = true;
24674  SigPrefNonConsecButton->Enabled = true;
24675  UnrestrictedButton->Enabled = true;
24676  RouteCancelButton->Enabled = true;
24677  PerformanceLogButton->Enabled = true;
24678  OperatorActionButton->Enabled = true;
24679  ExitOperationButton->Enabled = true;
24680  OperateButton->Enabled = false;
24681  SaveSessionButton->Enabled = false;
24682  TTClockAdjButton->Enabled = false;
24683 
24684  //await host acknowledgement
24685  Utilities->CallLogPop(2340);
24686  }
24687  catch(const Exception &e)
24688  {
24689  ErrorLog(232, e.Message);
24690  }
24691 }
24692 
24693 //---------------------------------------------------------------------------
24694 
24695 void __fastcall TInterface::MPCPHostIPEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
24696 {
24697  try
24698  {
24699  TrainController->LogEvent("MPCPIPEditBoxKeyUp," + AnsiString(Key));
24700  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPCPIPEditBoxKeyUp," + AnsiString(Key));
24701  if(Key == '\x0D') //CR
24702  {
24704  {
24705  ShowMessage("Format should be 'a.b.c.d' where a, b, c, and d are numbers between 0 and 255.\n\nObtain the address from the host and enter exactly as given.");
24706  MPCPHostIPEditBox->Text = "";
24707  Utilities->CallLogPop(2360);
24708  return;
24709  }
24710  else
24711  {
24712  MPCPHostIPEditBox->Enabled = false;
24713  if((MPCPHostPortEditBox->Enabled == false) && (MPCPPlayerNameEditBox->Enabled == false))
24714  {
24715  MPPlayerClient->Host = MPCPHostIPEditBox->Text;
24716  MPPlayerClient->Port = MPCPHostPortEditBox->Text.ToInt();
24717  MPCPSendButton->Enabled = true;
24718  }
24719  }
24720  }
24721  else
24722  {
24723  for(int x = 1; x <= MPCPHostIPEditBox->Text.Length(); x++)
24724  {
24725  if((MPCPHostIPEditBox->Text[x] != '.') && ((MPCPHostIPEditBox->Text[x] < '0') || (MPCPHostIPEditBox->Text[x] > '9')))
24726  {
24727  ShowMessage("Format should be 'a.b.c.d' where a, b, c, and d are numbers between 0 and 255.\n\nObtain the address from the host and enter exactly as given.");
24728  MPCPHostIPEditBox->Text = "";
24729  Utilities->CallLogPop(2361);
24730  return;
24731  }
24732  }
24733  }
24734  Utilities->CallLogPop(2362);
24735  }
24736  catch(const Exception &e)
24737  {
24738  ErrorLog(233, e.Message);
24739  }
24740 }
24741 
24742 //---------------------------------------------------------------------------
24743 
24744 void __fastcall TInterface::MPCPHostPortEditBoxKeyUp(TObject *Sender, WORD &Key,
24745  TShiftState Shift)
24746 {
24747  try
24748  {
24749  TrainController->LogEvent("MPCPHostPortEditBoxKeyUp," + AnsiString(Key));
24750  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPCPHostPortEditBoxKeyUp," + AnsiString(Key));
24751  if(Key == '\x0D') //CR
24752  {
24753  if((MPCPHostPortEditBox->Text == "") || (MPCPHostPortEditBox->Text.Length() < 5) || (MPCPHostPortEditBox->Text.ToInt() < 49152) || (MPCPHostPortEditBox->Text.ToInt() > 59999))
24754  {
24755  ShowMessage("Entry should be a number between 49152 and 59999.\n\nObtain the port number from the host and enter exactly as given.");
24756  MPCPHostPortEditBox->Text = "";
24757  Utilities->CallLogPop(2363);
24758  return;
24759  }
24760  MPCPHostPortEditBox->Enabled = false;
24761  if((MPCPHostIPEditBox->Enabled == false) && (MPCPPlayerNameEditBox->Enabled == false))
24762  {
24763  MPPlayerClient->Host = MPCPHostIPEditBox->Text;
24764  MPPlayerClient->Port = MPCPHostPortEditBox->Text.ToInt();
24765  MPCPSendButton->Enabled = true;
24766  }
24767  }
24768  else
24769  {
24770  for(int x = 1; x <= MPCPHostPortEditBox->Text.Length(); x++)
24771  {
24772  if((MPCPHostPortEditBox->Text[x] < '0') || (MPCPHostPortEditBox->Text[x] > '9'))
24773  {
24774  ShowMessage("Entry should be a number between 49152 and 59999.\n\nObtain the port number from the host and enter exactly as given.");
24775  MPCPHostPortEditBox->Text = "";
24776  Utilities->CallLogPop(2364);
24777  return;
24778  }
24779  }
24780  }
24781  Utilities->CallLogPop(2365);
24782  }
24783  catch(const Exception &e)
24784  {
24785  ErrorLog(234, e.Message);
24786  }
24787 }
24788 //---------------------------------------------------------------------------
24789 
24790 void __fastcall TInterface::MPCPPlayerNameEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
24791 {
24792  try
24793  {
24794  TrainController->LogEvent("MPCPPlayerNameEditBoxKeyUp," + AnsiString(Key));
24795  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MPCPPlayerNameEditBoxKeyUp," + AnsiString(Key));
24796  MPCPLabel3->Caption = "Player name (2 to 4 characters)";
24797  if(MPCPPlayerNameEditBox->Text.Length() > 0)
24798  {
24799  if(Key == '\x0D') //CR
24800  {
24801  if(MPCPPlayerNameEditBox->Text.Length() < 2)
24802  {
24803  ShowMessage("Entry should have at least two and at most four characters with no numbers or special characters.");
24804  MPCPPlayerNameEditBox->Text = "";
24805  Utilities->CallLogPop(2366);
24806  return;
24807  }
24808  else
24809  {
24811  MPCPPlayerNameEditBox->Enabled = false;
24812  if((MPCPHostIPEditBox->Enabled == false) && (MPCPHostPortEditBox->Enabled == false))
24813  {
24814  MPPlayerClient->Host = MPCPHostIPEditBox->Text;
24815  MPPlayerClient->Port = MPCPHostPortEditBox->Text.ToInt();
24816  MPCPSendButton->Enabled = true;
24817  }
24818  }
24819  }
24820  else
24821  {
24822  for(int x = 1; x <= MPCPPlayerNameEditBox->Text.Length(); x++)
24823  {
24824  if((MPCPPlayerNameEditBox->Text[x] < 'A') || ((MPCPPlayerNameEditBox->Text[x] > 'Z') && (MPCPPlayerNameEditBox->Text[x] < 'a'))
24825  || (MPCPPlayerNameEditBox->Text[x] > 'z'))
24826  {
24827  ShowMessage("Entry should have at least two and at most four characters with no numbers or special characters.");
24828  MPCPPlayerNameEditBox->Text = "";
24829  Utilities->CallLogPop(2367);
24830  return;
24831  }
24832  }
24833  }
24834  }
24835  Utilities->CallLogPop(2368);
24836  }
24837  catch(const Exception &e)
24838  {
24839  ErrorLog(235, e.Message);
24840  }
24841 }
24842 
24843 //---------------------------------------------------------------------------
24844 
24845 void TInterface::BuildDatagramFromPlayerMap(int Caller, char marker, AnsiString UserName, TBytes &buffer, TDynamicMap DynamicMap)
24846 { //datagram contents: marker + username + ;(if < 4 chars) + multiple[usernumber + H lower + H higher + V lower + V higher]
24847  // all but marker & username from DynamicMap
24848  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildDatagramFromPlayerMap, " + AnsiString(marker) + ',' + UserName);
24849  int bufCounter;
24850  buffer.Length = 8192; //initial value, reduced later
24851  buffer[0] = marker;
24852  for(bufCounter = 1; bufCounter <= UserName.Length(); bufCounter++)
24853  {
24854  buffer[bufCounter] = UserName[bufCounter];
24855  }
24856  if(UserName.Length() < 4)
24857  {
24858  buffer[bufCounter] = ';'; //marker for end of username
24859  bufCounter++;
24860  }
24861 //AnsiString DMIt->second.ServiceReference
24862 //short DMIt->second.RepeatNumber
24863 //short DMIt->second.TimeToExitSecs
24864 
24865  for(TDynamicMap::iterator DMIt = DynamicMap.begin(); DMIt != DynamicMap.end(); DMIt++)
24866  {
24867  buffer[bufCounter] = DMIt->first.first; //number
24868  bufCounter++;
24869  buffer[bufCounter] = DMIt->first.second.first & 0x00FF; //H lower
24870  bufCounter++;
24871  buffer[bufCounter] = (DMIt->first.second.first & 0xFF00) / 256; //H higher
24872  bufCounter++;
24873  buffer[bufCounter] = DMIt->first.second.second & 0x00FF; //V lower
24874  bufCounter++;
24875  buffer[bufCounter] = (DMIt->first.second.second & 0xFF00) / 256; //v higher
24876  bufCounter++;
24877  DMIt->second.ServiceReference = DMIt->second.ServiceReference.Trim();
24878  for(int x = 1; x <= DMIt->second.ServiceReference.Length(); x++)
24879  {
24880  buffer[bufCounter] = DMIt->second.ServiceReference[x];
24881  bufCounter++;
24882  }
24883  if(DMIt->second.ServiceReference.Length() < 8)
24884  {
24885  buffer[bufCounter] = ';'; //marker for end of service ref
24886  bufCounter++;
24887  }
24888  buffer[bufCounter] = DMIt->second.RepeatNumber & 0x00FF;
24889  bufCounter++;
24890  buffer[bufCounter] = (DMIt->second.RepeatNumber & 0xFF00) / 256;
24891  bufCounter++;
24892  buffer[bufCounter] = DMIt->second.TimeToExitSecs & 0x00FF;
24893  bufCounter++;
24894  buffer[bufCounter] = (DMIt->second.TimeToExitSecs & 0xFF00) / 256;
24895  bufCounter++;
24896 /* add if need to limit buffer length
24897  if(bufCounter > 490) //last value is 507 as starts at 0 & 17 max bytes for each loop, allows 29 exits/entries
24898  {
24899  break;
24900  }
24901 */
24902  }
24903  buffer.Length = bufCounter; //bufCounter incremented value = length since starts at 0
24904  Utilities->CallLogPop(2379);
24905 }
24906 
24907 //---------------------------------------------------------------------------
24908 
24909 bool TInterface::BuildDynamicMapFromPlayerDatagram(int Caller, TDynamicMap &DMap, TBytes Buffer, unsigned char &marker, AnsiString &UserName)
24910 {//datagrams of this type (most) are of form marker (1 byte), username (up to 4 bytes), then a series of TNumHVPairs
24911 //unlikely to be in alphabetical order, build map in same order as datagram
24912  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildDynamicMapFromPlayerDatagram");
24913  TDynamicMapEntry DMEntry;
24914  TNumHVPair NumHVPair;
24915  int y = 5; //highest NumHVPair start position
24916  DMap.clear();
24917  marker = Buffer[0];
24918  UserName = " ";
24919  for(int x = 1; x < 5; x++)
24920  {
24921  if((Buffer[x] < ' ') || (Buffer[x] > '~'))
24922  {
24923  DMap.clear();
24924  Utilities->CallLogPop(2380);
24925  return(false);
24926  }
24927  if(Buffer[x] == ';')
24928  {
24929  break;
24930  }
24931  }
24932  UserName[1] = Buffer[1]; //always at least 1 character
24933  UserName[2] = Buffer[2];
24934  if(UserName[2] == ';') //1 char only
24935  {
24936  UserName.Delete(2,3);
24937  y = 3;
24938  }
24939  else
24940  {
24941  UserName[3] = Buffer[3];
24942  if(UserName[3] == ';') //2 chars
24943  {
24944  UserName.Delete(3,2);
24945  y = 4;
24946  }
24947  else
24948  {
24949  UserName[4] = Buffer[4];
24950  if(UserName[4] == ';') //3 chars
24951  {
24952  UserName.Delete(4,1);
24953  y = 5;
24954  }
24955  }
24956  }
24957  while(y < (Buffer.Length - 9)) //9 allows for zero length service ref
24958  {
24959  TServiceInfo ServInfo; //ServiceReference + RepeatNumber + TimeToExitSecs (need new default values for each loop)
24960  NumHVPair.first = Buffer[y]; //number
24961  NumHVPair.second.first = Buffer[y+ 1] + (256 * Buffer[y + 2]); //H
24962  NumHVPair.second.second = Buffer[y + 3] + (256 * Buffer[y + 4]); //V
24963  if(!NumHVPairCheckOK(NumHVPair))
24964  {
24965  DMap.clear();
24966  Utilities->CallLogPop(2381);
24967  return(false);
24968  }
24969  y += 5;
24970  int z = 0;
24971  while((Buffer[y + z] != ';') && (z < 8))
24972  {
24973  ServInfo.ServiceReference[z + 1] = Buffer[y + z];
24974  z++;
24975  }
24976  ServInfo.ServiceReference = ServInfo.ServiceReference.Trim();
24977  y += ServInfo.ServiceReference.Length();
24978  if(Buffer[y] == ';')
24979  {
24980  y++; //skip past if there is one
24981  }
24982  ServInfo.RepeatNumber = Buffer[y] + (256 * Buffer[y + 1]);
24983  ServInfo.TimeToExitSecs = Buffer[y + 2] + (256 * Buffer[y + 3]);
24984  y += 4;
24985  if(!ServInfo.CheckOK() && ServInfo.ServiceReference != "")
24986  {
24987  DMap.clear();
24988  Utilities->CallLogPop(2382);
24989  return(false);
24990  }
24991  DMEntry.first = NumHVPair;
24992  DMEntry.second = ServInfo;
24993  DMap.insert(DMEntry);
24994  }
24995  Utilities->CallLogPop(2383);
24996  return(true);
24997 }
24998 
24999 //---------------------------------------------------------------------------
25000 
25001 void TInterface::BuildDatagramFromHostMap(int Caller, TBytes &buffer, TDynamicMap DynamicMap)
25002 { //datagram contents: TTTime as 32 bit integer representing hundredths of a second + multiple[usernumber + H lower + H higher + V lower + V higher]
25003  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildDatagramFromHostMap");
25004  int bufCounter = 0;
25005  buffer.Length = 8192; //initial value, reduced later
25006  unsigned int TTTime = double(TrainController->TTClockTime) * 8640000;
25007  buffer[0] = TTTime % 256;
25008  TTTime /= 256;
25009  buffer[1] = TTTime % 256;
25010  TTTime /= 256;
25011  buffer[2] = TTTime % 256;
25012  TTTime /= 256;
25013  buffer[3] = TTTime % 256;
25014  bufCounter += 4;
25015  for(TDynamicMap::iterator DMIt = DynamicMap.begin(); DMIt != DynamicMap.end(); DMIt++)
25016  {
25017  buffer[bufCounter] = DMIt->first.first; //number
25018  bufCounter++;
25019  buffer[bufCounter] = DMIt->first.second.first & 0x00FF; //H lower
25020  bufCounter++;
25021  buffer[bufCounter] = (DMIt->first.second.first & 0xFF00) / 256; //H higher
25022  bufCounter++;
25023  buffer[bufCounter] = DMIt->first.second.second & 0x00FF; //V lower
25024  bufCounter++;
25025  buffer[bufCounter] = (DMIt->first.second.second & 0xFF00) / 256; //v higher
25026  bufCounter++;
25027  DMIt->second.ServiceReference = DMIt->second.ServiceReference.Trim();
25028  for(int x = 1; x <= DMIt->second.ServiceReference.Length(); x++)
25029  {
25030  buffer[bufCounter] = DMIt->second.ServiceReference[x];
25031  bufCounter++;
25032  }
25033  if(DMIt->second.ServiceReference.Length() < 8)
25034  {
25035  buffer[bufCounter] = ';'; //marker for end of service ref
25036  bufCounter++;
25037  }
25038  buffer[bufCounter] = DMIt->second.RepeatNumber & 0x00FF;
25039  bufCounter++;
25040  buffer[bufCounter] = (DMIt->second.RepeatNumber & 0xFF00) / 256;
25041  bufCounter++;
25042  buffer[bufCounter] = DMIt->second.TimeToExitSecs & 0x00FF;
25043  bufCounter++;
25044  buffer[bufCounter] = (DMIt->second.TimeToExitSecs & 0xFF00) / 256;
25045  bufCounter++;
25046  }
25047  buffer.Length = bufCounter; //bufCounter incremented value = length since starts at 0
25048  Utilities->CallLogPop(2394);
25049 }
25050 
25051 //---------------------------------------------------------------------------
25052 
25053 bool TInterface::BuildDynamicMapFromHostDatagram(int Caller, int TTTime, TDynamicMap &DMap, TBytes Buffer)
25054 {
25055  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildDynamicMapFromHostDatagram");
25056  TDynamicMapEntry DMEntry;
25057  TNumHVPair NumHVPair;
25058  int y = 4; //NumHVPair start position
25059  DMap.clear();
25060  TTTime = Buffer[0] + (256 * Buffer[1]) + (65536 * Buffer[2]) + (16777216 * Buffer[3]);
25061  if((TTTime < 0) || (TTTime > 34560000)) //34560000 = hundredths of a second in 4 x 24 hrs
25062  {
25063  DMap.clear();
25064  Utilities->CallLogPop(2396);
25065  return(false);
25066  }
25067  while(y < (Buffer.Length - 9)) //9 allows for zero length service ref
25068  {
25069  TServiceInfo ServInfo; //ServiceReference + RepeatNumber + TimeToExitSecs (need new default values for each loop)
25070  NumHVPair.first = Buffer[y]; //number
25071  if(NumHVPair.first != OwnRlyUserNumber)
25072  {
25073  DMap.clear();
25074  Utilities->CallLogPop(2397);
25075  return(false);
25076  }
25077  NumHVPair.second.first = Buffer[y+ 1] + (256 * Buffer[y + 2]); //H
25078  NumHVPair.second.second = Buffer[y + 3] + (256 * Buffer[y + 4]); //V
25079  if(!NumHVPairCheckOK(NumHVPair))
25080  {
25081  DMap.clear();
25082  Utilities->CallLogPop(2398);
25083  return(false);
25084  }
25085  y += 5;
25086  int z = 0;
25087  while((Buffer[y + z] != ';') && (z < 8))
25088  {
25089  ServInfo.ServiceReference[z + 1] = Buffer[y + z];
25090  z++;
25091  }
25092  ServInfo.ServiceReference = ServInfo.ServiceReference.Trim();
25093  y += ServInfo.ServiceReference.Length();
25094  if(Buffer[y] == ';')
25095  {
25096  y++; //skip past if there is one
25097  }
25098  ServInfo.RepeatNumber = Buffer[y] + (256 * Buffer[y + 1]);
25099  ServInfo.TimeToExitSecs = Buffer[y + 2] + (256 * Buffer[y + 3]);
25100  y += 4;
25101  if(!ServInfo.CheckOK() && ServInfo.ServiceReference != "")
25102  {
25103  DMap.clear();
25104  Utilities->CallLogPop(2399);
25105  return(false);
25106  }
25107  DMEntry.first = NumHVPair;
25108  DMEntry.second = ServInfo;
25109  DMap.insert(DMEntry);
25110  }
25111  Utilities->CallLogPop(2400);
25112  return(true);
25113 }
25114 
25115 //---------------------------------------------------------------------------
25116 
25117 void TInterface::BuildDummyTestMap(TDynamicMap &DMap, std::ifstream &ExitFile) //<--temporary function for testing purposes
25118 { //ExitFile is a list of H & V values as char[] integers with '\n' delimiters between each and between each pair
25119  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildDummyTestMap");
25120  TDynamicMapEntry DMapEntry;
25121  TServiceInfo ServiceInfo; //null & zero values on construction
25122  THVShortPair ShortPair;
25123  unsigned char UserNum;
25124  while(!ExitFile.eof())
25125  {
25126  ExitFile >> UserNum; //number
25127  UserNum -= 48; //convert from character to ordinal
25128  if(ExitFile.eof()) //only get eof after an unsuccessful read attempt
25129  {
25130  continue;
25131  }
25132  ExitFile >> ShortPair.first; //H
25133  if(ExitFile.eof()) //only get eof after an unsuccessful read attempt
25134  {
25135  continue;
25136  }
25137  ExitFile >> ShortPair.second; //V
25138  if(ExitFile.eof())
25139  {
25140  continue;
25141  }
25142  DMapEntry.first.first = UserNum;
25143  DMapEntry.first.second = ShortPair;
25144  DMapEntry.second = ServiceInfo;
25145  DMap.insert(DMapEntry);
25146  }
25147  Utilities->CallLogPop(2384);
25148 }
25149 
25150 //---------------------------------------------------------------------------
25151 
25153 {
25154 //The player calls this prior to sending DynMapToHost, i.e. all the coupled linkages with railwaynumbers
25155 //typedef std::pair<TNumHVPair, TServiceInfo> TDynamicMapEntry;
25156 //typedef std::multimap<TNumHVPair, TExitInfo> TTimeToExitMultiMap;
25157  Utilities->CallLog.push_back(Utilities->TimeStamp() + "UpdateDynamicMapFromTimeToExitMultiMap");
25158  TDynamicMapEntry DMEntry;
25159  TDynamicMap::iterator DMIt;
25160  TNumHVPair NumHVPair;
25161 
25162  TTimeToExitMultiMap::iterator TTEMMIt = TrainController->TimeToExitMultiMap.begin();
25163  while(TTEMMIt != TrainController->TimeToExitMultiMap.end())
25164  {
25165  NumHVPair.first = OwnRlyUserNumber;
25166  NumHVPair.second = TTEMMIt->first;
25167  DMIt = DMap.find(NumHVPair);
25168  if(DMIt != DMap.end()) //else skip it, not included in coupling map
25169  {
25170  DMIt->second.ServiceReference = TTEMMIt->second.ServiceReference.Trim();
25171  DMIt->second.RepeatNumber = TTEMMIt->second.RepeatNumber;
25172  DMIt->second.TimeToExitSecs = TTEMMIt->second.TimeToExitSecs;
25173  }
25174  TTEMMIt++;
25175  }
25176  Utilities->CallLogPop(2385);
25177 }
25178 
25179 //---------------------------------------------------------------------------
25180 
25181 bool TInterface::InvalidIPAddress(AnsiString Text)
25182 {
25183  try
25184  {
25185  int Dot1 = 0, Dot2 = 0, Dot3 = 0;
25186  AnsiString Num1 = "",Num2 = "",Num3 = "",Num4 = "";
25187  if(Text.Length() < 7)
25188  {
25189  return true;
25190  }
25191  for(int x = 1; x <= Text.Length(); x++)
25192  {
25193  if(Text[x] == '.')
25194  {
25195  if(Dot1 == 0)
25196  {
25197  Dot1 = x;
25198  }
25199  else if(Dot2 == 0)
25200  {
25201  Dot2 = x;
25202  }
25203  else if(Dot3 == 0)
25204  {
25205  Dot3 = x;
25206  }
25207  }
25208  }
25209  if((Dot1 ==0) || (Dot2 ==0) || (Dot3 ==0))
25210  {
25211  return true; //less than 3 dots
25212  }
25213  if(Text.Length() == Dot3)
25214  {
25215  return true; //last dot at end
25216  }
25217  Num1 = Text.SubString(1, Dot1 - 1);
25218  Num2 = Text.SubString(Dot1 + 1, Dot2 - Dot1 - 1);
25219  Num3 = Text.SubString(Dot2 + 1, Dot3 - Dot2 - 1);
25220  Num4 = Text.SubString(Dot3 + 1, Text.Length() - Dot3);
25221  if((Num1 == "") || (Num2 == "") || (Num3 == "") || (Num4 == ""))
25222  {
25223  return true; //any number string empty
25224  }
25225  if((Num1.ToInt() > 255) ||(Num2.ToInt() > 255) ||(Num3.ToInt() > 255) ||(Num4.ToInt() > 255)) //EConvertError thrown if not an integer
25226  {
25227  return true;
25228  }
25229  if((Num1.ToInt() < 0) ||(Num2.ToInt() < 0) ||(Num3.ToInt() < 0) ||(Num4.ToInt() < 0))
25230  {
25231  return true;
25232  }
25233  return false;
25234  }
25235  catch(const EConvertError &e) //non-integer should have been caught earlier but include for completeness
25236  {
25237  return true;
25238  }
25239 }
25240 
25241 //---------------------------------------------------------------------------
25242 
25243 TInterface::TServiceInfo::TServiceInfo() //default constructor , same as TExitInfo() in TrainUnit
25244 {
25245  ServiceReference = " ";
25246  RepeatNumber = 0;
25247  TimeToExitSecs = -1;
25248 }
25249 
25250 //---------------------------------------------------------------------------
25251 
25253 {
25254  RlyUserNumber = 0; //allocated numbers start from 1
25255  RailwayName = "";
25256  UserName = "";
25257  UserIP = "";
25258  UserPort = 0;
25259 }
25260 
25261 //---------------------------------------------------------------------------
25262 
25263 bool TInterface::RlyToNum(AnsiString RailwayName, unsigned char &RlyUserNumber)
25264 {
25265  if(InfoVector.empty())
25266  {
25267  return(false);
25268  }
25269  TIVIt IVIt;
25270  for(IVIt = InfoVector.begin(); IVIt != InfoVector.end(); IVIt++)
25271  {
25272  if(IVIt->RailwayName == RailwayName)
25273  {
25274  RlyUserNumber = IVIt->RlyUserNumber;
25275  return(true);
25276  }
25277  }
25278  return(false);
25279 }
25280 
25281 //---------------------------------------------------------------------------
25282 
25283 bool TInterface::UserToNum(AnsiString UserName, unsigned char &RlyUserNumber)
25284 {
25285  if(InfoVector.empty())
25286  {
25287  return(false);
25288  }
25289  TIVIt IVIt;
25290  for(IVIt = InfoVector.begin(); IVIt != InfoVector.end(); IVIt++)
25291  {
25292  if(IVIt->UserName == UserName)
25293  {
25294  RlyUserNumber = IVIt->RlyUserNumber;
25295  return(true);
25296  }
25297  }
25298  return(false);
25299 }
25300 
25301 //---------------------------------------------------------------------------
25302 
25303 bool TInterface::NumToRly(unsigned char RlyUserNumber, AnsiString &RailwayName)
25304 {
25305  if(InfoVector.empty())
25306  {
25307  return(false);
25308  }
25309  TIVIt IVIt;
25310  for(IVIt = InfoVector.begin(); IVIt != InfoVector.end(); IVIt++)
25311  {
25312  if(IVIt->RlyUserNumber == RlyUserNumber)
25313  {
25314  RailwayName = IVIt->RailwayName;
25315  return(true);
25316  }
25317  }
25318  return(false);
25319 }
25320 
25321 //---------------------------------------------------------------------------
25322 
25323 bool TInterface::UserToIPAndPort(AnsiString UserName, AnsiString &UserIP, short UserPort)
25324 {
25325  if(InfoVector.empty())
25326  {
25327  return(false);
25328  }
25329  TIVIt IVIt;
25330  for(IVIt = InfoVector.begin(); IVIt != InfoVector.end(); IVIt++)
25331  {
25332  if(IVIt->UserName == UserName)
25333  {
25334  UserIP = IVIt->UserIP;
25335  UserPort = IVIt->UserPort;
25336  return(true);
25337  }
25338  }
25339  return(false);
25340 }
25341 
25342 //---------------------------------------------------------------------------
25343 
25344 bool TInterface::NumToIPAndPort(unsigned char RlyUserNumber, AnsiString &UserIP, short UserPort)
25345 {
25346  if(InfoVector.empty())
25347  {
25348  return(false);
25349  }
25350  TIVIt IVIt;
25351  for(IVIt = InfoVector.begin(); IVIt != InfoVector.end(); IVIt++)
25352  {
25353  if(IVIt->RlyUserNumber == RlyUserNumber)
25354  {
25355  UserIP = IVIt->UserIP;
25356  UserPort = IVIt->UserPort;
25357  return(true);
25358  }
25359  }
25360  return(false);
25361 }
25362 
25363 //---------------------------------------------------------------------------
25364 
25366 {
25367  if(NumHVPair.first > 100) //100 players max
25368  {
25369  return(false);
25370  }
25371  if((NumHVPair.second.first > 2000) || (NumHVPair.second.first < -2000))
25372  {
25373  return(false);
25374  }
25375  if((NumHVPair.second.second > 2000) || (NumHVPair.second.second < -2000))
25376  {
25377  return(false);
25378  }
25379  return(true);
25380 }
25381 
25382 //---------------------------------------------------------------------------
25383 
25385 {
25386  if(!TrainController->CheckHeadCodeValidity(13, false, ServiceReference)) //false for no messages
25387  {
25388  return(false);
25389  }
25390  if((RepeatNumber < 0) || (RepeatNumber > 6000)) //allows minute repeats for 4 days
25391  {
25392  return(false);
25393  }
25394  if((TimeToExitSecs < -1) || (TimeToExitSecs > 3600))
25395  {
25396  return(false);
25397  }
25398  return(true);
25399 }
25400 
25401 //---------------------------------------------------------------------------
25402 
25403 void TInterface::RemovePlayerFromStringGridAndInfoVector(int Caller, AnsiString PlayerUserName)
25404 {
25405  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemovePlayerFromStringGridAndInfoVector, " + PlayerUserName);
25406  for(int x = 0; x < NumPlayers; x++)
25407  {
25408  if(MultiplayerHostStringGrid->Cells[0][x + 2] == PlayerUserName)
25409  {
25410  MultiplayerHostStringGrid->Cells[0][x + 2] = "";
25411  MultiplayerHostStringGrid->Cells[2][x + 2] = "No";
25412  break;;
25413  }
25414  }
25415  if(!InfoVector.empty())//clear InfoVector of all but railway name
25416  {
25417  for(int x = 0; x < NumPlayers; x++)
25418  {
25419  if(InfoVector.at(x).UserName == PlayerUserName)
25420  {
25421 // InfoVector.at(x).RlyUserNumber = 0; //no, the number stays as is
25422  InfoVector.at(x).UserName = "";
25423  InfoVector.at(x).UserIP = "";
25424  InfoVector.at(x).UserPort = 0;
25425  break;;
25426  }
25427  }
25428  }
25429  Utilities->CallLogPop(2390);
25430 }
25431 
25432 //---------------------------------------------------------------------------
25433 
25434 void __fastcall TInterface::ShowHideStringGridMenuItemClick(TObject *Sender)
25435 {
25436  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ShowHideStringGridMenuItemClick");
25437  TrainController->LogEvent("ShowHideStringGridMenuItemClick");
25438  if(MultiplayerHostStringGrid->Visible)
25439  {
25440  MultiplayerHostStringGrid->Visible = false;
25441  }
25442  else
25443  {
25444  MultiplayerHostStringGrid->Visible = true;
25445  }
25446  Utilities->CallLogPop(2413);
25447 }
25448 
25449 //---------------------------------------------------------------------------
25450 
25452 {
25453  try
25454  {
25455  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlayerHandshakingActions");
25456  if(PlayerFiveSecondTimer == 0) //send at 5 sec intervals
25457  {
25458  EIdExceptionSource = "PlayerFiveSecondTimer";
25459  if(PlayerMakingInitialContactFlag) //sends it every 5 secs until host responds & then PlayerMakingInitialContactFlag reset
25460  {
25461  EIdExceptionSource += " PlayerMakingInitialContactFlag";
25462  //load datagram - Marker ('1') + UserName + ';' + RailwayName (no space or delimier between marker & railway name)
25463  UnicodeString Data = UnicodeString('1') + MPCPUserName + UnicodeString(';') + RailwayTitle;
25464  MPPlayerClient->Send(Data);
25465  }
25466  else if(PlayerReadyToBeginFlag)
25467  {
25468  EIdExceptionSource += " PlayerReadyToBeginFlag";
25469  //load datagram - Marker = '2' + UserName + times to exit (service ref, exit H&V & time) from DynMapToHost
25470  TBytes buffer;
25473  MPPlayerClient->SendBuffer(MPPlayerClient->Host, MPPlayerClient->Port, buffer);
25475  LastHostDataReceived = TDateTime(0);
25476  }
25477  else if(PlayerInSessionFlag)
25478  {
25479  EIdExceptionSource += " PlayerInSessionFlag5SecTimer";
25480  TBytes buffer;
25482  BuildDatagramFromPlayerMap(1, '5', MPCPUserName, buffer, DynMapToHost); //buffer length is set within this function
25483  MPPlayerClient->SendBuffer(MPPlayerClient->Host, MPPlayerClient->Port, buffer);
25484  //check last message time
25485  if(((TDateTime::CurrentDateTime() - LastHostDataReceived) > TDateTime(0.00034722)) && (LastHostDataReceived > TDateTime(1))) //== 30secs
25486  {
25487  //update all times to entry by 30 secs & have any enter that are due in that time (missed at least 4)
25488  //also when any train enters check that it's not already entered and ignore if so (Service ref + repeat number defines)
25490  if(ConsecutiveSelfUpdates > 10) //at least 5 minutes with no contact
25491  {
25492  //cancel session for this player
25493  }
25494  }
25495  }
25496  else
25497  {
25498  //default, probably won't need it
25499  }
25500  }
25501 
25502  if(PlayerOneSecondTimer == 10) //send at 1 sec intervals, use 10 so out of step with 5 sec timer
25503  {
25504  if(PlayerCancelJoinFlag) //send every second until acknowledged
25505  {
25506  //send message to host, marker = 3, username; nothing else, '3' tells host of the cancellation
25507  EIdExceptionSource += " PlayerCancelJoinFlag";
25508  //load datagram - Marker ('3') + UserName
25509  UnicodeString Data = UnicodeString('3') + MPCPUserName;
25510  MPPlayerClient->Send(Data);
25511  }
25513  {
25514  EIdExceptionSource += " PlayerAwaitingHostStartFlag";
25515  //load datagram - Marker ('4') + UserName
25516  UnicodeString Data = UnicodeString('4') + MPCPUserName;
25517  MPPlayerClient->Send(Data);
25518  }
25519  else if(PlayerInSessionFlag)
25520  {
25521  EIdExceptionSource += " PlayerInSessionFlag1SecTimer";
25522  UnicodeString Data = UnicodeString('6') + MPCPUserName;
25523  MPPlayerClient->Send(Data);
25524  }
25525  }
25526 
25527 //here player checks for any messages from host - after intial contact or speed changes etc during multiplay (every cycle)
25528  if(PlayerMakingInitialContactFlag) //receive
25529  {
25530  EIdExceptionSource = "PlayerMakingInitialContactFlag every cycle";
25531 // UnicodeString HostMessage = MPPlayerClient->ReceiveString(10);
25532  TBytes Buffer;
25533  Buffer.Length = 8192; //have to set long enough initially, reduced later
25534  Buffer.Length = MPPlayerClient->ReceiveBuffer(Buffer, 10); //<-- ReceiveBuffer
25535  if(Buffer.Length != 0)
25536  {
25537  PlayerMakingInitialContactFlag = false; //only if reply received
25538  if((Buffer[0] == 'T') && (Buffer[1] == 'h') && (Buffer[2] == 'e')) //error message
25539  {
25540  UnicodeString HostMessage = BytesToString(Buffer);
25541  ShowMessage(HostMessage);
25542  MPCPSendButton->Enabled = false;
25543  MPCPReadyToBeginButton->Enabled = false;
25544  MPCPPlayerNameEditBox->Text = "";
25545  MPCPHostPortEditBox->Text = "";
25546  MPCPHostIPEditBox->Text = "";
25547  PlayerReadyToBeginFlag = false;
25548  PlayerCancelJoinFlag = false;
25550  PlayerInSessionFlag = false;
25551  MultiplayerPlayerPanel->Visible = false;
25552  Track->MultiplayerOverlayMap.clear();
25554  }
25555  else //receive 'raw' coupled map for this player - own NumHVPair + coupled NumHVPair with default service info
25556  { //compile initial DynMapFromHost & DynMapToHost, & add overlays to the coupled exit graphics
25557  TServiceInfo ServiceInfo; //default values
25558  THVShortPair ShortPair;
25559  unsigned char UserNumber;
25560  TDynamicMapEntry DMEntry;
25561  DynMapFromHost.clear();
25562  DynMapToHost.clear();
25563  OwnRlyUserNumber = Buffer[0];
25564  for(int x = 0; x < (Buffer.Length - 9); x += 10)
25565  {
25566  UserNumber = Buffer[x];
25567  ShortPair.first = Buffer[x + 1] + (256 * Buffer[x + 2]);
25568  ShortPair.second = Buffer[x + 3] + (256 * Buffer[x + 4]);
25569  DMEntry.first.first = UserNumber;
25570  DMEntry.first.second = ShortPair;
25571  DMEntry.second = ServiceInfo;
25572  DynMapFromHost.insert(DMEntry);
25573  UserNumber = Buffer[x + 5];
25574  ShortPair.first = Buffer[x + 6] + (256 * Buffer[x + 7]);
25575  ShortPair.second = Buffer[x + 8] + (256 * Buffer[x + 9]);
25576  DMEntry.first.first = UserNumber;
25577  DMEntry.first.second = ShortPair;
25578  DMEntry.second = ServiceInfo;
25579  DynMapToHost.insert(DMEntry);
25580  }
25581  //Build Track->MultiplayerOverlayMap from DynMapFromHost, it consists of key = THVPair & value = graphic pointer
25582  Track->MultiplayerOverlayMap.clear();
25583  for(TDMIt DMIt = DynMapFromHost.begin(); DMIt != DynMapFromHost.end(); DMIt++)
25584  {
25585  typedef std::pair<int, int> THLocVLocPair;
25586  THLocVLocPair HVPair;
25587  std::pair<THLocVLocPair, Graphics::TBitmap*> MPOMEntry;
25588  int SpeedTag;
25589  Graphics::TBitmap *GrPtr;
25590  HVPair.first = int(DMIt->first.second.first);
25591  HVPair.second = int(DMIt->first.second.second);
25592  SpeedTag = Track->GetTrackElementFromTrackMap(4, HVPair.first, HVPair.second).SpeedTag;
25593  if((SpeedTag < 80) || (SpeedTag > 87))
25594  {
25595  throw Exception("Error, SpeedTag not a continuation in DynMapFromHost, value is " + AnsiString(SpeedTag));
25596  }
25597  else if(SpeedTag == 80)
25598  {
25599  GrPtr = RailGraphics->CouplingExit4;
25600  }
25601  else if(SpeedTag == 81)
25602  {
25603  GrPtr = RailGraphics->CouplingExit6;
25604  }
25605  else if(SpeedTag == 82)
25606  {
25607  GrPtr = RailGraphics->CouplingExit8;
25608  }
25609  else if(SpeedTag == 83)
25610  {
25611  GrPtr = RailGraphics->CouplingExit2;
25612  }
25613  else if(SpeedTag == 84)
25614  {
25615  GrPtr = RailGraphics->CouplingExit1;
25616  }
25617  else if(SpeedTag == 85)
25618  {
25619  GrPtr = RailGraphics->CouplingExit3;
25620  }
25621  else if(SpeedTag == 86)
25622  {
25623  GrPtr = RailGraphics->CouplingExit7;
25624  }
25625  else if(SpeedTag == 87)
25626  {
25627  GrPtr = RailGraphics->CouplingExit9;
25628  }
25629  MPOMEntry.first = HVPair;
25630  MPOMEntry.second = GrPtr;
25631  Track->MultiplayerOverlayMap.insert(MPOMEntry);
25632  }
25634  MPCPLabel2->Caption = "When ready click 'Ready to begin'"; //top box
25635  MPCPLabel4->Caption = "Joining request accepted"; //opposite image
25636  MPCPLabel7->Caption = ""; //Lower box top
25637  MPCPLabel8->Caption = ""; //Lower box bottom
25638  MPCPHostImage->Picture->Assign(RailGraphics->SolidCircleGreen);
25639  MPCPReadyToBeginButton->Enabled = true;
25640  }
25641  }
25642  }
25643  else if(PlayerReadyToBeginFlag)
25644  {
25645  EIdExceptionSource = "PlayerReadyToBegin every cycle";
25646  TBytes Buffer;
25647  Buffer.Length = 8192; //have to set long enough initially, reduced later
25648  Buffer.Length = MPPlayerClient->ReceiveBuffer(Buffer, 10); //<-- ReceiveBuffer
25649  if(Buffer.Length != 0)
25650  {
25651  if(BytesToString(Buffer) == "Await simulation start")
25652  {
25653  PlayerReadyToBeginFlag = false;
25655  MPCPReadyToBeginButton->Enabled = false;
25656  MPCPLabel2->Caption = "Awaiting simulation start"; //top box
25657  MPCPLabel4->Caption = ""; //opposite image
25658  MPCPLabel7->Caption = ""; //Lower box top
25659  MPCPLabel8->Caption = ""; //Lower box bottom
25660  MPCPLabel5->Caption = ""; //Host IP
25661  MPCPLabel6->Caption = ""; //Host Port
25662  MPCPLabel3->Caption = ""; //UserName
25663  MPCPHostIPEditBox->Visible = false;
25664  MPCPHostPortEditBox->Visible = false;
25665  MPCPPlayerNameEditBox->Visible = false;
25666  MPCPHostImage->Visible = false;
25667  }
25668  else
25669  {
25670  //do nothing, leave PlayerReadyToStart true & send message again
25671  }
25672  }
25673  else
25674  {
25675  //do nothing, leave PlayerReadyToStart true & send message again
25676  }
25677  }
25678  else if(PlayerCancelJoinFlag)
25679  {
25680  EIdExceptionSource = "PlayerCancelJoinFlag every cycle";
25681  TBytes Buffer;
25682  Buffer.Length = 8192; //have to set long enough initially, reduced later
25683  Buffer.Length = MPPlayerClient->ReceiveBuffer(Buffer, 10); //<-- ReceiveBuffer
25684  if(Buffer.Length != 0)
25685  {
25686  if(BytesToString(Buffer) == "Cancelled")
25687  {
25688  PlayerCancelJoinFlag = false;
25689  }
25690  }
25691  }
25692  else if(PlayerAwaitingHostStartFlag) //await start message then clear the joining box, set PlayerMultiplayerInSession & reset PlayerAwaitingHostStart
25693  {
25694  EIdExceptionSource = "PlayerAwaitingHostStartFlag every cycle";
25695  TBytes Buffer;
25696  Buffer.Length = 8192; //have to set long enough initially, reduced later
25697  Buffer.Length = MPPlayerClient->ReceiveBuffer(Buffer, 10); //<-- ReceiveBuffer
25698  if(Buffer.Length != 0)
25699  {
25700  if(BytesToString(Buffer) == "Start Session")
25701  {
25703  PlayerInSessionFlag = true;
25704  MultiplayerPlayerPanel->Visible = false;
25705  OperatingPanelLabel->Caption = "Operation";
25706  OperateButton->Click(); //keep speed etc. buttons disabled
25707  }
25708  }
25709  }
25710  else if(PlayerInSessionFlag)
25711  {
25712  EIdExceptionSource = "PlayerMultiplayerInSession every cycle";
25713  TBytes Buffer;
25714  int TTTime;
25715  TDynamicMap DMap;
25716  TDynamicMap::iterator DMIt, DMFHIt;
25717  Buffer.Length = 8192; //have to set long enough initially, reduced later
25718  Buffer.Length = MPPlayerClient->ReceiveBuffer(Buffer, 10); //<-- ReceiveBuffer
25719  if(Buffer.Length != 0)
25720  {
25721  //here have DynMapFromHost as buffer with TTClockTime at start as 32 bit integer
25723  if(BuildDynamicMapFromHostDatagram(0, TTTime, DMap, Buffer)) //validity checks in this function
25724  {
25725  //store TTTime & update DynMapFromHost, should be in proper order but don't rely on it
25726  TrainController->TTClockTime = double(TTTime) / 8640000;
25727  for(DMIt = DMap.begin(); DMIt != DMap.end(); DMIt++)
25728  {
25729  DMFHIt = DynMapFromHost.find(DMIt->first);
25730  if(DMFHIt != DynMapFromHost.end())
25731  {
25732  DMFHIt->second = DMIt->second;
25733  }
25734  //else skip it
25735  }
25736  LastHostDataReceived = TDateTime::CurrentDateTime();
25737 
25738  //now have TTClock updated + service refs & times to entry in DynMapFromHost
25739 
25740  }
25741  //else skip it - catch up next time
25742  }
25743  }
25744  Utilities->CallLogPop(2416);
25745  }
25746  catch(const EIdException &e) //non-error catch
25747 //if no response from peer then get a 'connection reset by peer' message which isn't valid
25748  {
25749  Utilities->CallLogPop(2417);
25750  }
25751  catch(const Exception &e)
25752  {
25753  ErrorLog(240, e.Message);
25754  }
25755 }
25756 
25757 //---------------------------------------------------------------------------
25758 
25759 /*
25760  Problems with ifstream reading (see 'SessionFileIntegrityCheck(AnsiString FileName)' above):-
25761 
25762  These problems were with Borland C++Builder 4.
25763 
25764  The functions saved in OldFiles\Backups220809Duringifstream testing were used for testing the odd behaviour where the
25765  ifstream pointer gave different characters using get() and getline(), when reading the timetable entries in the session
25766  file for 20/08/09 at 18:45 (saved). All was well until point 48677 in the session file, when for some reason the
25767  getline(0 & get(0 gave different results. Many earlier timetable strings had been read OK before that, and it wasn't
25768  clear what was special about this particular string.
25769  Later more detailed study found that on reading the string beginning at point 48605 (i.e. the one earlier than above),
25770  within function CheckNoNewLineAtStartNonZeroTerminatedFileString the file pointer (using tellg()) reduced from 48606 to
25771  48604 after reading the 'F' character. Thereafter characters were read correctly but the pointer remained 2 too low.
25772  This is thought to be a flaw in the compiler.
25773  Later again additional tellg()s and a seekg()s were included in CheckNoNewLineAtStartNonZeroTerminatedFileString, and
25774  though these should have had no effect they somehow caused the next getline() within CheckTimetableFromSessionFile to
25775  read a null, even though the pointer had been reset to its value before the call to
25776  CheckNoNewLineAtStartNonZeroTerminatedFileString. Again this seems to be a flaw in the compiler, where the pointer
25777  that is indicated by tellg and the true pointer within the system can be different.
25778  Tried the old c++ stream library to see if that worked but it was exactly the same. Probably because the same code is
25779  used for both with the new library just defined within the std namespace.
25780  Success!! Traced to the putback function failing. It (apparently) can't be used if the file pointer has been altered
25781  after the last read that is to be put back. Corrected that & the most recent session file checked out & loaded OK.
25782  (note - don't need the ifstream file to be open in output mode for the putback to work)
25783  But: the earlier file - 18:45 as above - still fails to advance the file pointer in the middle of checking the
25784  timetable, it sticks at position 48601. This position points to 'r' in 'Frh' just before a newline. Also the file
25785  integrity is OK up to and after this sticking point. Oddly though the loading function works fine (i.e. by bypassing
25786  the integrity check function), though the timetable isn't read directly, it is copied to a new stand-alone timetable
25787  file and that read by the program.
25788  Created a new version of CheckNoNewLineAtStartNonZeroTerminatedFileString with 'New' at end, & got rid of all the
25789  internal digressions & getlines. This passed the earlier sticking point, but stuck later at 48677, i.e. the 'h' from
25790  'Frh' at the end of the entry following that for the earlier sticking point. Here
25791  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew works fine, with end pointer correctly set at 48680, i.e. after the
25792  newline, but the subsequent getline() function, although it retrieves the line correctly, the file pointer is set to
25793  48677, i.e. before the newline, so getline seems to fail to extract the newline character. Still to check - why doesn't
25794  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew see 'h' instead of '0' in the subsequent read? If it did the two
25795  would tally, though would still be wrong.
25796  Further investigation:- CheckNoNewLineAtStartNonZeroTerminatedFileStringNew doesn't seem to recognize the file pointer
25797  as set by seekg at 48677. It continues to read at the point it left off earlier, whereas getline() does read at 48677
25798  & recovers 'h'. Continuing to apply getline() after the above effect it is found that it doesn't extract newlines after
25799  reading further lines, but extracts them when read alone i.e. it reads a line then a null in succession, although the
25800  lines are only separated by single newline characters.
25801 
25802  Need to check:
25803  1. Does the file read correctly if only get() functions used without getline() and without resetting the file pointer?
25804  2. Does the file read correctly if only getline() functions used without get() and without resetting the file pointer?
25805  3. Does the file read correctly if get() functions alternated with getline() but without resetting the file pointer?
25806 
25807  For 1: Still goes wrong at usual place, reads 'h' at the same point. Try not resetting the file pointer with seekg.
25808  Tried this - got past the earlier point but failed later with a reduction in file pointer after a character read. In
25809  fact the reduction was by 40 bytes for reading a single comma! Try without any tellg's - yes, that got past all the
25810  timetable OK. So, works OK with just get() providing no tellg's (& no seekg's).
25811 
25812  For 2: Works OK using getline().
25813 
25814  For 3: Gets to end of timetable OK but the next tellg gives a wrong value. Check if using getline() alone gives a
25815  wrong tellg. Tried getline() alone, reached end of TT as before, but gave the same wrong file pos on using tellg.
25816  Try continuing to see if works OK in spite of tellg giving wrong result. Yes it works OK. Hence the problem seems to
25817  be tellg, which sometimes returns wrong results, and they corrupt things when used in seekg.
25818 
25819  Overall conclusion: Avoid all tellg's & seekg's. If need to reset a file position then close and reopen it.
25820 */
25821 
25822 // ---------------------------------------------------------------------------
TInterface::NumToRly
bool NumToRly(unsigned char RlyUserNumber, AnsiString &RailwayName)
Definition: InterfaceUnit.cpp:25303
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17760
TInterface::SpeedButton59
TSpeedButton * SpeedButton59
Definition: InterfaceUnit.h:601
TInterface::CopyTTEntryButtonClick
void __fastcall CopyTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3790
TInterface::CtrlKey
bool CtrlKey
true when the CTRL key is pressed (see also ShiftKey)
Definition: InterfaceUnit.h:1227
TInterface::MTBFEditBox
TEdit * MTBFEditBox
Definition: InterfaceUnit.h:519
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11428
TInterface::BecomeNewServiceMenuItemClick
void __fastcall BecomeNewServiceMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12493
TInterface::ScreenLeftButtonClick
void __fastcall ScreenLeftButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9233
TInterface::ExitMenuItem
TMenuItem * ExitMenuItem
Definition: InterfaceUnit.h:454
TTrain::AllowedToPassRedSignal
bool AllowedToPassRedSignal
set when train has been called on, or when under signaller control and instructed to pass a red signa...
Definition: TrainUnit.h:378
TInterface::TextMoveVPos
int TextMoveVPos
used to store the original text 'H' & 'V' positions for use during text moving
Definition: InterfaceUnit.h:1411
TInterface::OperMode
@ OperMode
Definition: InterfaceUnit.h:986
TInterface::CPDirectionsCheckBox
TCheckBox * CPDirectionsCheckBox
Definition: InterfaceUnit.h:698
TTrain::ZeroPowerNoNewShuttleFromNonRepeatMessage
bool ZeroPowerNoNewShuttleFromNonRepeatMessage
Definition: TrainUnit.h:345
TInterface::SpeedButton140
TSpeedButton * SpeedButton140
Definition: InterfaceUnit.h:682
TTrain::ZeroPowerNoNewServiceMessage
bool ZeroPowerNoNewServiceMessage
Definition: TrainUnit.h:344
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TInterface::TDynamicMapComp::operator()
bool operator()(const TNumHVPair &lower, const TNumHVPair &higher) const
< Dynamic map comparator based on Num then H & V
Definition: InterfaceUnit.cpp:23859
TPrefDirElement::SetEXGraphicPtr
void SetEXGraphicPtr(Graphics::TBitmap *input)
Used in pasting pref dirs.
Definition: TrackUnit.h:364
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11401
TInterface::AddPrefDirButton
TBitBtn * AddPrefDirButton
Definition: InterfaceUnit.h:151
TInterface::RemoveTrainMenuItem
TMenuItem * RemoveTrainMenuItem
Definition: InterfaceUnit.h:506
TInterface::LocationNamesSetImage
TImage * LocationNamesSetImage
Definition: InterfaceUnit.h:315
TInterface::SpeedLimitBox
TEdit * SpeedLimitBox
distance/speed setting edit box that accepts speed limits
Definition: InterfaceUnit.h:127
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TInterface::SaveImageAndGridMenuItemClick
void __fastcall SaveImageAndGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2743
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TTrainController
Handles all train and timetable activities, only one object created.
Definition: TrainUnit.h:697
TInterface::FloatingInfoMenu
TMenuItem * FloatingInfoMenu
Definition: InterfaceUnit.h:481
TInterface::SpeedButton34
TSpeedButton * SpeedButton34
Definition: InterfaceUnit.h:576
TInterface::NewTTEntryKeyFlag
bool NewTTEntryKeyFlag
Definition: InterfaceUnit.h:1332
TInterface::ConflictAnalysisButtonClick
void __fastcall ConflictAnalysisButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:15069
TInterface::CallingOnButton
TSpeedButton * CallingOnButton
Definition: InterfaceUnit.h:240
TInterface::BuildTrainDataVectorForValidateFile
bool BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
Check the integrity of a stored timetable file (either as a stand alone file or within a session file...
Definition: InterfaceUnit.cpp:20952
TInterface::SpeedButton42
TSpeedButton * SpeedButton42
Definition: InterfaceUnit.h:584
TInterface::SelectBitmapMouseLocX
int SelectBitmapMouseLocX
when flag SelectPickedUp is set to true (see above - to allow a selected screen area to move during M...
Definition: InterfaceUnit.h:1384
TInterface::PrefDirPanel
TPanel * PrefDirPanel
'Set preferred directions' panel
Definition: InterfaceUnit.h:396
TInterface::PrefDirPanelLabel
TLabel * PrefDirPanelLabel
label to the left of PrefDirPanel
Definition: InterfaceUnit.h:342
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12947
TInterface::MTBFEditBoxKeyUp
void __fastcall MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:14859
TInterface::TrackMode
@ TrackMode
Definition: InterfaceUnit.h:986
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1692
TInterface::SaveSessionButton
TBitBtn * SaveSessionButton
Definition: InterfaceUnit.h:236
TInterface::TTLabel2
TLabel * TTLabel2
Definition: InterfaceUnit.h:377
TInterface::ElapsedTimerRunning
bool ElapsedTimerRunning
Definition: InterfaceUnit.h:1179
TInterface::TTClockx1ButtonClick
void __fastcall TTClockx1ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14458
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TInterface::LengthConversionPanel
TPanel * LengthConversionPanel
Definition: InterfaceUnit.h:140
TInterface::SpeedButton143
TSpeedButton * SpeedButton143
Definition: InterfaceUnit.h:685
TTrain::ChangeTrainDirection
void ChangeTrainDirection(int Caller, bool NoLogFlag)
Reverses the direction of motion of the train.
Definition: TrainUnit.cpp:6378
TInterface::ChangeDirectionMenuItem
TMenuItem * ChangeDirectionMenuItem
Definition: InterfaceUnit.h:500
TTrain::MidEntryPos
int MidEntryPos
Definition: TrainUnit.h:366
TTrainController::RebuildOpTimeToActMultimap
void RebuildOpTimeToActMultimap(int Caller)
new v2.2.0 for OperatorActionPanel
Definition: TrainUnit.cpp:19964
TTrainController::PwrHigh
bool PwrHigh
Definition: TrainUnit.h:805
TInterface::StepForwardMenuItem
TMenuItem * StepForwardMenuItem
Definition: InterfaceUnit.h:503
TTrack::SelectGraphicVector
TUserGraphicVector SelectGraphicVector
Definition: TrackUnit.h:796
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:91
TInterface::DelayMenu
TMenuItem * DelayMenu
Definition: InterfaceUnit.h:751
SignallerMoveForwards
@ SignallerMoveForwards
Definition: TrainUnit.h:53
TInterface::SignallerControlStopMenuItem
TMenuItem * SignallerControlStopMenuItem
Definition: InterfaceUnit.h:505
TRailGraphics::ConvertSignalsToOppositeHand
void ConvertSignalsToOppositeHand(int Caller)
Converts all signal graphics to opposite hand new at v2.3.0.
Definition: GraphicUnit.cpp:4430
TInterface::FormResize
void __fastcall FormResize(TObject *Sender)
Definition: InterfaceUnit.cpp:14730
TInterface::SpeedButton70
TSpeedButton * SpeedButton70
Definition: InterfaceUnit.h:612
TInterface::SpeedButton144
TSpeedButton * SpeedButton144
Definition: InterfaceUnit.h:686
TInterface::SpeedButton32
TSpeedButton * SpeedButton32
Definition: InterfaceUnit.h:574
TInterface::SaveTTAsButtonClick
void __fastcall SaveTTAsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4260
TInterface::MPCPLabel2
TLabel * MPCPLabel2
Definition: InterfaceUnit.h:721
TInterface::SelectBitmapHLoc
int SelectBitmapHLoc
the original (prior to moving & after finished moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1382
TInterface::OperatorActionButton
TBitBtn * OperatorActionButton
Definition: InterfaceUnit.h:237
TInterface::DistanceKey
TImage * DistanceKey
information panel displayed when setting distances & speed limits
Definition: InterfaceUnit.h:305
AboutUnit.h
Arrive
@ Arrive
Definition: TrainUnit.h:52
TInterface::OperatorActionPanelDragStartX
int OperatorActionPanelDragStartX
mouse 'X' position when the OperatorActionPanel begins to be dragged
Definition: InterfaceUnit.h:1370
TInterface::SpeedButton54
TSpeedButton * SpeedButton54
Definition: InterfaceUnit.h:596
TInterface::PasteWarningSentFlag
bool PasteWarningSentFlag
indicates that the warning message about pasting overwriting the area has been given,...
Definition: InterfaceUnit.h:1257
TInterface::StartWholeRailwayMoveVPos
int StartWholeRailwayMoveVPos
mouse Y position when start to move the whole railway
Definition: InterfaceUnit.h:1397
TTrain::ZeroPowerNoCDTMessage
bool ZeroPowerNoCDTMessage
Definition: TrainUnit.h:343
TTrain::CallingOnFlag
bool CallingOnFlag
calling on permitted
Definition: TrainUnit.h:384
TInterface::UnrestrictedButton
TBitBtn * UnrestrictedButton
Definition: InterfaceUnit.h:232
TTrainController::CheckHeadCodeValidity
bool CheckHeadCodeValidity(int Caller, bool GiveMessages, AnsiString HeadCode)
Returns true if the headcode complies with requirements.
Definition: TrainUnit.cpp:11598
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:797
TRailGraphics::SpeedBut72NormBlackGlyph
Graphics::TBitmap * SpeedBut72NormBlackGlyph
Definition: GraphicUnit.h:1064
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12987
TInterface::ExportTTMenuItemClick
void __fastcall ExportTTMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3154
TInterface::RestoreTTKeyFlag
bool RestoreTTKeyFlag
Definition: InterfaceUnit.h:1338
TInterface::CancelSelectionMenuItemClick
void __fastcall CancelSelectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10931
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3686
TInterface::PERFLOG_DIR_NAME
static const UnicodeString PERFLOG_DIR_NAME
Definition: InterfaceUnit.h:999
TInterface::MPHPOwnPortEditBoxKeyUp
void __fastcall MPHPOwnPortEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:23766
TInterface::WholeRailwayMoving
bool WholeRailwayMoving
true when moving the railway with the mouse, new at v2.1.0
Definition: InterfaceUnit.h:1317
TInterface::TDynamicMapEntry
std::pair< TNumHVPair, TServiceInfo > TDynamicMapEntry
Definition: InterfaceUnit.h:1087
TInterface::TextFoundFlag
bool TextFoundFlag
indicates that a text item has been found when clicking on a build screen during 'AddText' or 'MoveTe...
Definition: InterfaceUnit.h:1291
TInterface::DisableRouteButtons
void DisableRouteButtons(int Caller)
Called during operation whenever the route type buttons need to be disabled, e.g. when paused.
Definition: InterfaceUnit.cpp:21789
TInterface::OperateRailwayMenuItemClick
void __fastcall OperateRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2071
TInterface::TCMIterator
TCouplingMap::iterator TCMIterator
Definition: InterfaceUnit.h:1100
TInterface::DerailImage
TImage * DerailImage
Definition: InterfaceUnit.h:301
TRailGraphics::CouplingExit2
Graphics::TBitmap * CouplingExit2
Definition: GraphicUnit.h:553
TTrain::MaxRunningSpeed
double MaxRunningSpeed
the current maximum train running speed
Definition: TrainUnit.h:426
TInterface::TTLabel3
TLabel * TTLabel3
Definition: InterfaceUnit.h:378
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:895
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:780
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:281
TRailGraphics::SpeedBut75NormBlackGlyph
Graphics::TBitmap * SpeedBut75NormBlackGlyph
Definition: GraphicUnit.h:1067
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7235
RestoreTimetableControl
@ RestoreTimetableControl
Definition: TrainUnit.h:53
TTrainController::LastSessionSaveTTClockTime
TDateTime LastSessionSaveTTClockTime
Definition: TrainUnit.h:708
TInterface::TTSelectedEntry
AnsiString TTSelectedEntry
used to record the current timetable entry when changing to AZ order or back to original order
Definition: InterfaceUnit.h:1208
TInterface::HostMultiplayInProgressFlag
bool HostMultiplayInProgressFlag
Definition: InterfaceUnit.h:1138
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:53
TAllRoutes::AutoSigsRoute
@ AutoSigsRoute
Definition: TrackUnit.h:1621
TInterface::SpeedButton19
TSpeedButton * SpeedButton19
Definition: InterfaceUnit.h:561
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5687
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7136
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5714
TActionVectorEntry::LocationType
TTimetableLocationType LocationType
indicates where the train is when the relevant action occurs
Definition: TrainUnit.h:142
TInterface::MasterClockTimer
void __fastcall MasterClockTimer(TObject *Sender)
Definition: InterfaceUnit.cpp:8356
TTrack::GapFlashGreenPosition
int GapFlashGreenPosition
Definition: TrackUnit.h:764
TInterface::MainScreen
TImage * MainScreen
the railway display screen
Definition: InterfaceUnit.h:322
TInterface::SpeedButton67
TSpeedButton * SpeedButton67
Definition: InterfaceUnit.h:609
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:66
TInterface::CutMenuItem
TMenuItem * CutMenuItem
Definition: InterfaceUnit.h:469
TInterface::SpeedButton120
TSpeedButton * SpeedButton120
Definition: InterfaceUnit.h:662
TInterface::LCResetCounter
unsigned int LCResetCounter
count up to 20 then resets - to check LCs & raise barriers if no route & no train present
Definition: InterfaceUnit.h:1358
TInterface::BlueBgndMenuItem
TMenuItem * BlueBgndMenuItem
Definition: InterfaceUnit.h:464
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1928
TInterface::TTLabel1
TLabel * TTLabel1
Definition: InterfaceUnit.h:376
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10323
TInterface::ModerateDelaysMenuItemClick
void __fastcall ModerateDelaysMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:23477
TInterface::ResetChangedFileDataAndCaption
void ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
Called whenever the railway is changed to deal with title displays (loaded railway and timetable) and...
Definition: InterfaceUnit.cpp:19504
TRailGraphics::CouplingExit3
Graphics::TBitmap * CouplingExit3
Definition: GraphicUnit.h:554
TInterface::ClpBrdValid
AnsiString ClpBrdValid
set to RlyClpBrdCopy or RlyClpBrd_Cut when Windows Clipboard contains a valid railway segment
Definition: InterfaceUnit.h:1184
TTrain::MaxBrakeRate
double MaxBrakeRate
the maximum brake rate that the train can achieve
Definition: TrainUnit.h:430
TInterface::SpeedButton52
TSpeedButton * SpeedButton52
Definition: InterfaceUnit.h:594
TInterface::LoadConfigFile
void LoadConfigFile(int Caller, bool FirstLoad)
Load the configuration file, only allow default track element length and speed limit to be loaded it ...
Definition: InterfaceUnit.cpp:15163
TInterface::IMAGE_DIR_NAME
static const UnicodeString IMAGE_DIR_NAME
Definition: InterfaceUnit.h:1001
TInterface::ShowPerformancePanel
bool ShowPerformancePanel
true when the 'show performance panel' button has been clicked during operation
Definition: InterfaceUnit.h:1285
TInterface::LoadSessionDialog
TOpenDialog * LoadSessionDialog
Definition: InterfaceUnit.h:527
TInterface::LoadCouplingFileDialog
TOpenDialog * LoadCouplingFileDialog
Definition: InterfaceUnit.h:706
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TInterface::OutputLog10MouseDown
void __fastcall OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13823
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:607
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2824
TInterface::BecomeNewServiceMenuItem
TMenuItem * BecomeNewServiceMenuItem
Definition: InterfaceUnit.h:750
TInterface::SpeedButton116
TSpeedButton * SpeedButton116
Definition: InterfaceUnit.h:658
TInterface::ReloadConfigMenuItem
TMenuItem * ReloadConfigMenuItem
Definition: InterfaceUnit.h:743
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5867
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:150
TTrain::MidExitPos
int MidExitPos
Definition: TrainUnit.h:366
TInterface::NewSelectBitmapVLoc
int NewSelectBitmapVLoc
as above for VLoc
Definition: InterfaceUnit.h:1368
TInterface::MoveTextOrGraphic
@ MoveTextOrGraphic
Definition: InterfaceUnit.h:1018
TInterface::ScreenGridButton
TBitBtn * ScreenGridButton
Definition: InterfaceUnit.h:107
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8163
TInterface::EditMenu
TMenuItem * EditMenu
Definition: InterfaceUnit.h:466
TTrain::TrainFailed
bool TrainFailed
Definition: TrainUnit.h:410
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:645
DisplayUnit.h
TInterface::ResetSelectRect
void ResetSelectRect()
SelectRect is the rectangle selected via the 'Edit'menu, and this function sets left,...
Definition: InterfaceUnit.cpp:22553
TInterface::TTClockAdjustWarningHide
bool TTClockAdjustWarningHide
true if user opts not to show the timetable clock adjustment warning (false on starting the program)
Definition: InterfaceUnit.h:1293
TInterface::TTLabel9
TLabel * TTLabel9
Definition: InterfaceUnit.h:384
TTrain::ZeroPowerNoFrontSplitMessage
bool ZeroPowerNoFrontSplitMessage
Definition: TrainUnit.h:339
TTrainController::SPADWarning
bool SPADWarning
Definition: TrainUnit.h:791
TInterface::TTClockAdjustCheckBox
TCheckBox * TTClockAdjustCheckBox
Definition: InterfaceUnit.h:264
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12726
TInterface::TrackNotLinkedImage
TImage * TrackNotLinkedImage
Definition: InterfaceUnit.h:312
TTrain::DepartureTimeSet
bool DepartureTimeSet
set when stopped at a location and the next action is departure (set in UpdateTrain when ReleaseTime ...
Definition: TrainUnit.h:386
TInterface::WarningHover
bool WarningHover
true when mouse hovers over warning messages during operation - to prevent clicking while changing
Definition: InterfaceUnit.h:1315
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7621
TInterface::SaveTTAsButton
TButton * SaveTTAsButton
Definition: InterfaceUnit.h:181
TInterface::ZoomButtonClick
void __fastcall ZoomButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9478
TInterface::SpeedButton90
TSpeedButton * SpeedButton90
Definition: InterfaceUnit.h:632
TTrain::LagElement
int LagElement
Definition: TrainUnit.h:366
TTrack::GetLocationName
AnsiString GetLocationName(unsigned int InactiveTrackVectorPosition)
Return location name for a given inactive track vector position.
Definition: TrackUnit.h:811
TTrainController::BufferAttentionWarning
bool BufferAttentionWarning
Definition: TrainUnit.h:791
TInterface::ExitTrackButtonClick
void __fastcall ExitTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1755
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9963
TInterface::SpeedButton135
TSpeedButton * SpeedButton135
Definition: InterfaceUnit.h:677
TInterface::SpeedButton111
TSpeedButton * SpeedButton111
Definition: InterfaceUnit.h:653
TInterface::RouteCancelFlag
bool RouteCancelFlag
true when route cancel button pressed, enables a right mouse click to cancel a route if in an appropr...
Definition: InterfaceUnit.h:1271
TTextHandler::LoadText
void LoadText(int Caller, std::ifstream &VecFile)
load the railway's text from VecFile
Definition: TextUnit.cpp:297
THVShortPair
std::pair< short, short > THVShortPair
Definition: InterfaceUnit.h:81
TInterface::SpeedToggleButton2Click
void __fastcall SpeedToggleButton2Click(TObject *Sender)
Definition: InterfaceUnit.cpp:13976
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14119
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:15540
TInterface::LoadNormalSignalGlyphs
void LoadNormalSignalGlyphs(int Caller)
In trackbuild display normal signal types on signal buttons.
Definition: InterfaceUnit.cpp:22804
TInterface::MPHPOwnIPEditBoxKeyUp
void __fastcall MPHPOwnIPEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:23715
TInterface::SkipEventsBeforeSameLoc
void SkipEventsBeforeSameLoc(int Caller, int TrainID, AnsiString LocationName)
< used when change early to the next service (Fns, Fns-sh, Frh-sh or F-nshs) to advance the action po...
Definition: InterfaceUnit.cpp:12732
TInterface::MainScreenMouseDown3
void MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-out mode.
Definition: InterfaceUnit.cpp:7539
TInterface::TTLabel11
TLabel * TTLabel11
Definition: InterfaceUnit.h:385
TInterface::CancelTTEntryButton
TButton * CancelTTEntryButton
Definition: InterfaceUnit.h:172
TInterface::SpeedButton8
TSpeedButton * SpeedButton8
Definition: InterfaceUnit.h:550
TInterface::UserGraphicVectorNumber
int UserGraphicVectorNumber
used to store a single item of user graphics
Definition: InterfaceUnit.h:1413
TInterface::PreviousTTEntryButton
TButton * PreviousTTEntryButton
Definition: InterfaceUnit.h:163
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17720
TInterface::TrackElementPanel
TPanel * TrackElementPanel
panel containing the track/location/parapet element buttons
Definition: InterfaceUnit.h:413
TInterface::MinorDelaysMenuItemClick
void __fastcall MinorDelaysMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:23465
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18556
TInterface::SelectionValid
bool SelectionValid
true when an area of screen has been selected via the 'Edit' & 'Select' or 'Reselect' menu items
Definition: InterfaceUnit.h:1277
TDisplay::InvertElement
void InvertElement(int Caller, int HPos, int VPos)
Definition: DisplayUnit.cpp:142
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:740
TInterface::TRlyUserInfo::UserName
AnsiString UserName
Definition: InterfaceUnit.h:1059
TInterface::OperateButtonClick
void __fastcall OperateButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2090
TInterface::WhiteBgndMenuItem
TMenuItem * WhiteBgndMenuItem
Definition: InterfaceUnit.h:462
TInterface::ContinuationAutoSignals
void ContinuationAutoSignals(int Caller, TDateTime Now)
Deal with signal resetting on auto signal routes that extend to continuations where trains have depar...
Definition: InterfaceUnit.cpp:17654
TTrainController::CrashWarning
bool CrashWarning
Definition: TrainUnit.h:791
TInterface::LoadInterface
void LoadInterface(int Caller, std::ifstream &SessionFile)
Load the interface part of a session file.
Definition: InterfaceUnit.cpp:20214
TInterface::SpeedButton2
TSpeedButton * SpeedButton2
Definition: InterfaceUnit.h:544
TTrain::PlotTrain
void PlotTrain(int Caller, TDisplay *Disp)
Plots the train on the display in normal (zoomed-in) mode.
Definition: TrainUnit.cpp:8658
TInterface::AutoSigsFlag
bool AutoSigsFlag
true when AutoSig route building selected during operation
Definition: InterfaceUnit.h:1215
TInterface::SetRouteButtonsInfoCaptionAndRouteNotStarted
void SetRouteButtonsInfoCaptionAndRouteNotStarted(int Caller)
Enables or disables the route type buttons depending on the route mode, sets the information panel me...
Definition: InterfaceUnit.cpp:21662
TInterface::MoveForwardsMenuItem
TMenuItem * MoveForwardsMenuItem
Definition: InterfaceUnit.h:501
TActionVectorEntry::DepartureTime
TDateTime DepartureTime
relevant times at which the action is timetabled, zeroed on creation so change to -1 as a marker for ...
Definition: TrainUnit.h:136
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:157
TInterface::YardEdit
TEdit * YardEdit
Definition: InterfaceUnit.h:135
TInterface::SkipListHeaderPanel
TPanel * SkipListHeaderPanel
Definition: InterfaceUnit.h:746
TInterface::SigPrefConsecButtonClick
void __fastcall SigPrefConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2155
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3662
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4455
TInterface::Paused
@ Paused
Definition: InterfaceUnit.h:1008
TTrainController::SaveSessionTrains
void SaveSessionTrains(int Caller, std::ofstream &SessionFile)
save trains to a session file
Definition: TrainUnit.cpp:15555
TInterface::SpeedButton41
TSpeedButton * SpeedButton41
Definition: InterfaceUnit.h:583
TInterface::TrackInfoMenuItem
TMenuItem * TrackInfoMenuItem
Definition: InterfaceUnit.h:482
TRailGraphics::SpeedBut73NormBlackGlyph
Graphics::TBitmap * SpeedBut73NormBlackGlyph
Definition: GraphicUnit.h:1065
TInterface::Operating
@ Operating
Definition: InterfaceUnit.h:1008
TTextHandler
A single object that handles text management.
Definition: TextUnit.h:62
TInterface::EditTimetableMenuItemClick
void __fastcall EditTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3312
TInterface::TakeSignallerControlMenuItemClick
void __fastcall TakeSignallerControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11677
TInterface::TimetableMode
@ TimetableMode
Definition: InterfaceUnit.h:986
TInterface::ScreenUpButtonClick
void __fastcall ScreenUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9417
TInterface::ShowHideTTButtonClick
void __fastcall ShowHideTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3490
TInterface::ImageMenu
TMenuItem * ImageMenu
Definition: InterfaceUnit.h:488
TInterface::LoadGroundSignalGlyphs
void LoadGroundSignalGlyphs(int Caller)
In trackbuild display ground signal types on signal buttons.
Definition: InterfaceUnit.cpp:22820
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TInterface::ReloadConfigMenuItemClick
void __fastcall ReloadConfigMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:15146
TInterface::CPArrivalsCheckBox
TCheckBox * CPArrivalsCheckBox
Definition: InterfaceUnit.h:277
TInterface::OneEntryTimetableMemo
TMemo * OneEntryTimetableMemo
the single service editing and display area on the right hand side of the timetable edit screen
Definition: InterfaceUnit.h:434
TInterface::SelectBitmapVLoc
int SelectBitmapVLoc
the original (prior to moving & after finished moving) VLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1388
TInterface::LengthOKButtonClick
void __fastcall LengthOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1383
session_api_
API * session_api_
Definition: InterfaceUnit.cpp:70
TInterface::SpeedButton47
TSpeedButton * SpeedButton47
Definition: InterfaceUnit.h:589
TInterface::OutputLog1MouseDown
void __fastcall OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13735
NotStarted
@ NotStarted
Definition: TrainUnit.h:88
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4615
TInterface::AppDeactivate
void __fastcall AppDeactivate(TObject *Sender)
Definition: InterfaceUnit.cpp:732
TInterface::UnrestrictedButtonClick
void __fastcall UnrestrictedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2234
TInterface::ExportTTMenuItem
TMenuItem * ExportTTMenuItem
Definition: InterfaceUnit.h:452
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6419
TInterface::SaveTTKeyFlag
bool SaveTTKeyFlag
Definition: InterfaceUnit.h:1336
TRailGraphics::SpeedBut71NormBlackGlyph
Graphics::TBitmap * SpeedBut71NormBlackGlyph
Definition: GraphicUnit.h:1063
TInterface::SelectNewGraphicClick
void __fastcall SelectNewGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:15007
TInterface::SpeedButtonClick
void __fastcall SpeedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:865
TTrack::GetHLocMax
int GetHLocMax()
Definition: TrackUnit.h:862
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3538
TInterface::CPEditArrRange
TEdit * CPEditArrRange
Definition: InterfaceUnit.h:280
TInterface::ErrorButtonClick
void __fastcall ErrorButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13117
TTrainController::SPADEvents
int SPADEvents
Definition: TrainUnit.h:844
TInterface::PasteTTEntryButton
TButton * PasteTTEntryButton
Definition: InterfaceUnit.h:167
TInterface::SpeedButton139
TSpeedButton * SpeedButton139
Definition: InterfaceUnit.h:681
TInterface::SpeedButton3
TSpeedButton * SpeedButton3
Definition: InterfaceUnit.h:545
TTrain::ZeroPowerNoRepeatShuttleMessage
bool ZeroPowerNoRepeatShuttleMessage
Definition: TrainUnit.h:346
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1297
TInterface::SetLevel2PrefDirMode
void SetLevel2PrefDirMode(int Caller)
Sets the Level2PrefDirMode user mode, using the Level2PrefDirMode variable to determine the mode.
Definition: InterfaceUnit.cpp:17332
TInterface::SetGapsButton
TBitBtn * SetGapsButton
Definition: InterfaceUnit.h:99
TTrain::ActionVectorEntryPtr
TActionVectorEntry * ActionVectorEntryPtr
points to the current position in the ActionVector (a member of the TTrainDataEntry class)
Definition: TrainUnit.h:372
TTrainDataEntry
Contains all data for a single timetable service entry.
Definition: TrainUnit.h:207
TPrefDirElement::SetXLinkPos
void SetXLinkPos(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:352
clSignalStopBackground
#define clSignalStopBackground
Definition: GraphicUnit.h:299
TTrainController::LateDeps
int LateDeps
Definition: TrainUnit.h:834
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:19030
TInterface::ExitMenuItemClick
void __fastcall ExitMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5667
TrackUnit.h
TInterface::SpeedButton29
TSpeedButton * SpeedButton29
Definition: InterfaceUnit.h:571
TInterface::SpeedButton35
TSpeedButton * SpeedButton35
Definition: InterfaceUnit.h:577
TInterface::ScreenDownButtonClick
void __fastcall ScreenDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9355
TInterface::api_oper_mode_
int api_oper_mode_
Definition: InterfaceUnit.h:1171
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:19225
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9534
TInterface::RlyToNum
bool RlyToNum(AnsiString RailwayName, unsigned char &RlyUserNumber)
Definition: InterfaceUnit.cpp:25263
TDisplay::ClearDisplay
void ClearDisplay(int Caller)
Empty the display.
Definition: DisplayUnit.cpp:183
TDisplay::Top
int Top()
Return the top pixel position of the screen.
Definition: DisplayUnit.h:121
TInterface::ExitPrefDirButtonClick
void __fastcall ExitPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2052
TTrainController::RebuildTimeToExitMultiMap
void RebuildTimeToExitMultiMap(int Caller)
new for multiplayer
Definition: TrainUnit.cpp:20135
TInterface::SaveErrorFile
void SaveErrorFile()
Save the error log after an error has been thrown - no need for a caller.
Definition: InterfaceUnit.cpp:21802
TTrain::SendMissedActionLogs
void SendMissedActionLogs(int Caller, int IncNum, TActionVectorEntry *Ptr)
Missed actions (see NameInTimetableBeforeCDT above) sent to the performance log and performance file.
Definition: TrainUnit.cpp:6522
TInterface::SpeedVariableLabel2
TLabel * SpeedVariableLabel2
Definition: InterfaceUnit.h:148
TInterface::TrainInfoMenuItem
TMenuItem * TrainInfoMenuItem
Definition: InterfaceUnit.h:484
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1514
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1600
TInterface::TrainStatusInfoOnOffMenuItemClick
void __fastcall TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5733
TInterface::SpeedButton96
TSpeedButton * SpeedButton96
Definition: InterfaceUnit.h:638
TInterface::TTClockxHalfButtonClick
void __fastcall TTClockxHalfButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14477
TInterface::OutputLog3
TLabel * OutputLog3
Definition: InterfaceUnit.h:331
TTextHandler::GetFontStyleAsInt
int GetFontStyleAsInt(int Caller, TFont *InputFont)
retrieve the style of the font as a coded integer
Definition: TextUnit.cpp:99
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
TOnePrefDir::ExternalStorePrefDirElement
void ExternalStorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map - used by other classes.
Definition: TrackUnit.h:1429
clB5G5R4
#define clB5G5R4
Definition: GraphicUnit.h:285
Utilities.h
TInterface::SetTrackModeEditMenu
void SetTrackModeEditMenu(int Caller)
Enables or disables the initial Edit mode submenu items in Track mode.
Definition: InterfaceUnit.cpp:22421
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:727
TTrain::SkippedDeparture
bool SkippedDeparture
< used for terminating a service early and becoming new follow-on service
Definition: TrainUnit.h:327
TInterface::SaveImageNoGridMenuItemClick
void __fastcall SaveImageNoGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2651
TInterface::SpeedButton25
TSpeedButton * SpeedButton25
Definition: InterfaceUnit.h:567
TInterface::HelpMenu
TMenuItem * HelpMenu
Definition: InterfaceUnit.h:494
TInterface::TrackOKButtonClick
void __fastcall TrackOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:946
TTrainController::CheckSessionLockedRoutes
bool CheckSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for locked routes, true for success.
Definition: TrainUnit.cpp:15658
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3262
TInterface::NoDelaysMenuItemClick
void __fastcall NoDelaysMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:23453
TInterface::GapsSetImage
TImage * GapsSetImage
Definition: InterfaceUnit.h:313
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15705
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TInterface::LocationNameComboBoxKeyUp
void __fastcall LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4833
TInterface::ClipboardChecked
bool ClipboardChecked
used to prevent Windows clipboard being checked repeatedly
Definition: InterfaceUnit.h:1219
TInterface::RevertToOriginalRouteSelector
void RevertToOriginalRouteSelector(int Caller)
Clears any route start markers, enables or disables the route cancel button, and resets the informati...
Definition: InterfaceUnit.cpp:15970
TInterface::FileIntegrityCheck
bool FileIntegrityCheck(int Caller, char *FileName) const
Check integrity of a railway file prior to loading, return true for success.
Definition: InterfaceUnit.cpp:15807
TInterface::OwnRlyUserNumber
unsigned char OwnRlyUserNumber
Definition: InterfaceUnit.h:1149
TInterface::TTLastServicePtr
TTEVPtr TTLastServicePtr
timetable entry value pointers used during timetable editing
Definition: InterfaceUnit.h:1454
TTrainController::CheckSessionTrains
bool CheckSessionTrains(int Caller, std::ifstream &InFile)
Part of the session file integrity check for train entries, true for success.
Definition: TrainUnit.cpp:15596
TInterface::CouplingFileLoadedFlag
bool CouplingFileLoadedFlag
Definition: InterfaceUnit.h:1139
TInterface::SpeedButton126
TSpeedButton * SpeedButton126
Definition: InterfaceUnit.h:668
TakeSignallerControl
@ TakeSignallerControl
Definition: TrainUnit.h:52
TInterface::PlayerMultiplayInProgressFlag
bool PlayerMultiplayInProgressFlag
Definition: InterfaceUnit.h:1142
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12792
Simple
@ Simple
Definition: TrackUnit.h:65
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:784
TTrain::ZeroPowerNoRepeatShuttleOrNewServiceMessage
bool ZeroPowerNoRepeatShuttleOrNewServiceMessage
flags to indicate whether the respective message has been sent
Definition: TrainUnit.h:347
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:45
TInterface::DeleteMenuItem
TMenuItem * DeleteMenuItem
Definition: InterfaceUnit.h:475
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2873
TInterface::TTClockAdjustOKButtonClick
void __fastcall TTClockAdjustOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:15024
TInterface::ChangeDirectionMenuItemClick
void __fastcall ChangeDirectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11896
TInterface::PointsFlashDuration
float PointsFlashDuration
duration of the flash period when changing points manually
Definition: InterfaceUnit.h:1347
TTrainController::TimeToExitMultiMap
TTimeToExitMultiMap TimeToExitMultiMap
Map of times to exit & exit coordinates.
Definition: TrainUnit.h:994
TInterface::LocationNameComboBoxClick
void __fastcall LocationNameComboBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4762
TInterface::TTServiceSyntaxCheckKeyFlag
bool TTServiceSyntaxCheckKeyFlag
Definition: InterfaceUnit.h:1334
TInterface::UserToNum
bool UserToNum(AnsiString UserName, unsigned char &RlyUserNumber)
Definition: InterfaceUnit.cpp:25283
TInterface::TLevel2OperMode
TLevel2OperMode
Definition: InterfaceUnit.h:1007
TInterface::ConsecSignalsRoute
bool ConsecSignalsRoute
true when AutoSig or preferred route building selected during operation (always same state as Preferr...
Definition: InterfaceUnit.h:1221
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1365
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13043
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3859
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5827
TTrain::BackgroundColour
TColor BackgroundColour
the background colour of the train's headcode graphics
Definition: TrainUnit.h:505
TInterface::LengthCancelButtonClick
void __fastcall LengthCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1590
TInterface::MPCPSendButton
TButton * MPCPSendButton
Definition: InterfaceUnit.h:714
TTrain
Definition: TrainUnit.h:304
TInterface::OutputLog5
TLabel * OutputLog5
Definition: InterfaceUnit.h:333
TTrainController::CheckTimeValidity
bool CheckTimeValidity(int Caller, AnsiString TimeStr, TDateTime &Time)
returns true if the time complies with requirements
Definition: TrainUnit.cpp:11178
clSignallerStopped
#define clSignallerStopped
Definition: GraphicUnit.h:298
TTextHandler::SelectTextVector
TTextVector SelectTextVector
Definition: TextUnit.h:69
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:152
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11442
TInterface::CallOnImage
TImage * CallOnImage
Definition: InterfaceUnit.h:298
TInterface::PerformancePanelDragStartY
int PerformancePanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1379
TInterface::LocationNameTextBox
TEdit * LocationNameTextBox
edit box that accepts location names
Definition: InterfaceUnit.h:129
TInterface::MPCPHostPortEditBoxKeyUp
void __fastcall MPCPHostPortEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:24744
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:626
TInterface::SaveSessionFlag
bool SaveSessionFlag
true when a session save command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:1273
TTrainController::ContinuationTrainExpectationMultiMap
TContinuationTrainExpectationMultiMap ContinuationTrainExpectationMultiMap
Multimap for TContinuationTrainExpectationEntry objects, the access key is the expectation time.
Definition: TrainUnit.h:868
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7636
TInterface::EndSimulationMenuItem
TMenuItem * EndSimulationMenuItem
Definition: InterfaceUnit.h:707
TInterface::SpeedButton73
TSpeedButton * SpeedButton73
Definition: InterfaceUnit.h:615
TInterface::TTLabel4
TLabel * TTLabel4
Definition: InterfaceUnit.h:379
TTrain::StoppedForTrainInFront
bool StoppedForTrainInFront
Definition: TrainUnit.h:482
TInterface::ConflictAnalysisKeyFlag
bool ConflictAnalysisKeyFlag
Definition: InterfaceUnit.h:1340
GapJump
@ GapJump
Definition: TrackUnit.h:65
TInterface::Level2OperMode
enum TInterface::TLevel2OperMode Level2OperMode
TInterface::SigsOnRightImage1
TImage * SigsOnRightImage1
Definition: InterfaceUnit.h:319
TInterface::UserToIPAndPort
bool UserToIPAndPort(AnsiString UserName, AnsiString &UserIP, short UserPort)
Definition: InterfaceUnit.cpp:25323
TInterface::SaveRailwayPDPButton
TBitBtn * SaveRailwayPDPButton
Save button on PrefDirPanel.
Definition: InterfaceUnit.h:154
TInterface::SpeedButton62
TSpeedButton * SpeedButton62
Definition: InterfaceUnit.h:604
TInterface::HostCombinedDynamicMap
TDynamicMap HostCombinedDynamicMap
Definition: InterfaceUnit.h:1103
TInterface::SpeedButton58
TSpeedButton * SpeedButton58
Definition: InterfaceUnit.h:600
TTrainController::MissedStops
int MissedStops
Definition: TrainUnit.h:837
TInterface::TempTTFileName
AnsiString TempTTFileName
the name for the temporary file used to save loaded timetables for storage in session files & error l...
Definition: InterfaceUnit.h:1206
TInterface::PrefDirMode
@ PrefDirMode
Definition: InterfaceUnit.h:986
TInterface::PassRedSignalMenuItem
TMenuItem * PassRedSignalMenuItem
Definition: InterfaceUnit.h:502
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7382
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:148
TRailGraphics::bmGreenRect
Graphics::TBitmap * bmGreenRect
Definition: GraphicUnit.h:521
TInterface::TTClockExitButtonClick
void __fastcall TTClockExitButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14337
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:148
TTrack::IsReadyForOperation
bool IsReadyForOperation(bool GiveMessage)
Indicates whether or not the railway is ready for saving as a '.rly' file and for operation.
Definition: TrackUnit.h:817
Finish
@ Finish
Definition: TrainUnit.h:77
TTrack::Raising
@ Raising
Definition: TrackUnit.h:607
TInterface::LastHostDataReceived
TDateTime LastHostDataReceived
player records this to allow updating when connection lost
Definition: InterfaceUnit.h:1106
TInterface::OAListBoxRightMouseButtonDown
bool OAListBoxRightMouseButtonDown
flag set when right mouse button clicked over op action list box, so floating information window show...
Definition: InterfaceUnit.h:1255
TTrainController::FinishedOperation
void FinishedOperation(int Caller)
called when exiting operation mode to delete all trains and timetable data etc
Definition: TrainUnit.cpp:9556
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10428
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TTrain::MidElement
int MidElement
Definition: TrainUnit.h:366
TTrackElement::TempTrackMarker23
bool TempTrackMarker23
Utility markers for program use.
Definition: TrackUnit.h:138
TInterface::SpeedButton5
TSpeedButton * SpeedButton5
Definition: InterfaceUnit.h:547
TInterface::LocationNameKeyUp
void __fastcall LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:1158
TInterface::LoadUserGraphicDialog
TOpenDialog * LoadUserGraphicDialog
Definition: InterfaceUnit.h:529
TAllRoutes::CallonVector
std::vector< TCallonEntry > CallonVector
the store of all call-on entries
Definition: TrackUnit.h:1660
TInterface::OutputLog8MouseDown
void __fastcall OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13803
TTrain::LeadElement
int LeadElement
Definition: TrainUnit.h:366
TInterface::SetPausedOrZoomedInfoCaption
void SetPausedOrZoomedInfoCaption(int Caller)
Sets the information panel message for zoom-out or paused modes.
Definition: InterfaceUnit.cpp:21770
TInterface::CurDir
AnsiString CurDir
the full path to the folder where railway.exe resides
Definition: InterfaceUnit.h:1192
TInterface::OneEntryTimetableMemoKeyUp
void __fastcall OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4790
TInterface::RouteCancelButton
TBitBtn * RouteCancelButton
Definition: InterfaceUnit.h:233
TInterface::SpeedButton26
TSpeedButton * SpeedButton26
Definition: InterfaceUnit.h:568
TPrefDirElement::SetELink
void SetELink(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:334
TInterface::HomeButton
TBitBtn * HomeButton
Definition: InterfaceUnit.h:288
TRailGraphics
Handles graphic data & functions, single object defined.
Definition: GraphicUnit.h:308
TInterface::OperatorActionPanelDragStartY
int OperatorActionPanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1372
TTrain::RepeatNumber
int RepeatNumber
indicates which of the repeating services this train represents (0 = first service)
Definition: TrainUnit.h:360
TTrainDataEntry::ActionVector
TActionVector ActionVector
all the actions for the train
Definition: TrainUnit.h:225
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:700
TInterface::NewHomeButton
TBitBtn * NewHomeButton
Definition: InterfaceUnit.h:289
TInterface::ResetAll
void ResetAll(int Caller)
Called during ClearEverything and on startup to reset all major railway data values.
Definition: InterfaceUnit.cpp:19316
TInterface::ConvertToOtherHandSignalsMenuItem
TMenuItem * ConvertToOtherHandSignalsMenuItem
Definition: InterfaceUnit.h:507
TInterface::SkipAllEventsBeforeNewService
void SkipAllEventsBeforeNewService(int Caller, int TrainID, int PtrAdvance)
Called for diagnostic purposes when keys CTRL ALT 4 pressed.
Definition: InterfaceUnit.cpp:12684
TInterface::MPCPLabel5
TLabel * MPCPLabel5
Definition: InterfaceUnit.h:728
TInterface::SpeedButton75
TSpeedButton * SpeedButton75
Definition: InterfaceUnit.h:617
TTrainController::LoadSessionLockedRoutes
void LoadSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
load locked routes from a session file
Definition: TrainUnit.cpp:15637
TInterface::DistancesMarked
bool DistancesMarked
true when setting lengths, used to ensure the screen distance markers are redisplayed when the screen...
Definition: InterfaceUnit.h:1231
TPrefDirElement::GetXLink
int GetXLink() const
Returns XLink.
Definition: TrackUnit.h:275
TInterface::PlayerInSessionFlag
bool PlayerInSessionFlag
Definition: InterfaceUnit.h:1147
TTrainController::EarlyPasses
int EarlyPasses
Definition: TrainUnit.h:830
TTrain::HeadCode
AnsiString HeadCode
needs own HeadCode because repeat entries will differ from TrainDataEntry.HeadCode
Definition: TrainUnit.h:323
TInterface::TrackBuildPanel
TPanel * TrackBuildPanel
'Build/modify railway' panel
Definition: InterfaceUnit.h:394
TInterface::SkipListExitImageClick
void __fastcall SkipListExitImageClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12476
TTrain::EntryTime
TDateTime EntryTime
Definition: TrainUnit.h:462
TInterface::CutMoving
@ CutMoving
Definition: InterfaceUnit.h:1019
TInterface::SpeedButton134
TSpeedButton * SpeedButton134
Definition: InterfaceUnit.h:676
TInterface::SelectLengthsMenuItem
TMenuItem * SelectLengthsMenuItem
Definition: InterfaceUnit.h:476
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1374
TInterface::SpeedButton72
TSpeedButton * SpeedButton72
Definition: InterfaceUnit.h:614
TInterface::ValidateTimetableButton
TButton * ValidateTimetableButton
Definition: InterfaceUnit.h:179
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6079
TInterface::UpdateDynamicMapFromTimeToExitMultiMap
void UpdateDynamicMapFromTimeToExitMultiMap(int Caller, TDynamicMap &DMap)
Convert TimeToExitMultiMap to an existing DynamicMap with all THVShortPairs listed.
Definition: InterfaceUnit.cpp:25152
TUserGraphicItem
Definition: DisplayUnit.h:31
TInterface::IPCheckLinkLabelLinkClick
void __fastcall IPCheckLinkLabelLinkClick(TObject *Sender, const UnicodeString Link, TSysLinkType LinkType)
Definition: InterfaceUnit.cpp:23819
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1520
InterfaceUnit.h
TInterface::CopyMenuItemClick
void __fastcall CopyMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9828
TInterface::PerformanceLogButton
TBitBtn * PerformanceLogButton
Definition: InterfaceUnit.h:235
TInterface::FORMATTEDTT_DIR_NAME
static const UnicodeString FORMATTEDTT_DIR_NAME
Definition: InterfaceUnit.h:1002
TInterface::HighLightOneGap
bool HighLightOneGap(int Caller, int &HLoc, int &VLoc)
Called during gap setting to mark a gap with a red ellipse and ask user to select the corresponding g...
Definition: InterfaceUnit.cpp:15716
TTrain::OneLengthAccelDecel
bool OneLengthAccelDecel
set when a train can only move forwards one element before stopping but needs to accelerate for the f...
Definition: TrainUnit.h:396
TTrain::FloatingLabelNextString
AnsiString FloatingLabelNextString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the 'Next' action.
Definition: TrainUnit.cpp:7120
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:618
TTrain::FailedTrainNoFinishJoinMessage
bool FailedTrainNoFinishJoinMessage
Definition: TrainUnit.h:341
TInterface::SpeedButton55
TSpeedButton * SpeedButton55
Definition: InterfaceUnit.h:597
TInterface::OperatorActionPanel
TPanel * OperatorActionPanel
new v2.2.0 panel housing the OAListBox with list of trains and times to act
Definition: InterfaceUnit.h:422
TInterface::NextTTEntryButton
TButton * NextTTEntryButton
Definition: InterfaceUnit.h:164
TTextHandler::SelectTextVectorSize
unsigned int SelectTextVectorSize(int Caller)
return the number of items in SelectTextVector
Definition: TextUnit.cpp:544
TInterface::TrackTrainFloat
void TrackTrainFloat(int Caller)
Controls the floating window function, called during the ClockTimer2 function.
Definition: InterfaceUnit.cpp:17711
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TInterface::AddLocationNameText
void AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
Add 'Name' to TextVector and display on screen at a position determined by the shape and size of the ...
Definition: InterfaceUnit.cpp:22585
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10537
TInterface::TAnsiCouplingMapComp::operator()
bool operator()(const TAnsiCouplingPair &lower, const TAnsiCouplingPair &higher) const
Definition: InterfaceUnit.cpp:23830
TInterface::TRlyUserInfo::RlyUserNumber
unsigned char RlyUserNumber
Definition: InterfaceUnit.h:1057
TRailGraphics::CouplingExit4
Graphics::TBitmap * CouplingExit4
Definition: GraphicUnit.h:555
TInterface::TDMIt
TDynamicMap::iterator TDMIt
Definition: InterfaceUnit.h:1096
TTextHandler::CheckTextElementsInFile
bool CheckTextElementsInFile(int Caller, std::ifstream &VecFile)
check the validity of text items in VecFile prior to loading, return true for success
Definition: TextUnit.cpp:366
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:299
TTrack::GetVLocMax
int GetVLocMax()
Definition: TrackUnit.h:872
TTrainController::LoadSessionContinuationAutoSigEntries
void LoadSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
load ContinuationAutoSigEntries from a session file
Definition: TrainUnit.cpp:15720
TInterface::MPCPCancelButtonClick
void __fastcall MPCPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:24625
TInterface::MPCPSendButtonClick
void __fastcall MPCPSendButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:24594
TInterface::HighlightOneEntryInAllEntriesTTListBox
void HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
Called during timetable editing to highlight in red a single entry in the list of all entries in the ...
Definition: InterfaceUnit.cpp:5591
TInterface::DistanceStart
@ DistanceStart
Definition: InterfaceUnit.h:1018
TInterface::ErrorMessage
TMemo * ErrorMessage
the text of the normal error message screen
Definition: InterfaceUnit.h:430
TInterface::ExitPrefDirButton
TBitBtn * ExitPrefDirButton
Definition: InterfaceUnit.h:156
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:792
TInterface::TIVIt
TInfoVector::iterator TIVIt
Definition: InterfaceUnit.h:1066
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:124
TRailGraphics::CouplingExit1
Graphics::TBitmap * CouplingExit1
Definition: GraphicUnit.h:552
TInterface::TrackLengthPanel
TPanel * TrackLengthPanel
the panel that contains the distance/speed setting buttons and edit boxes
Definition: InterfaceUnit.h:415
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:788
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3833
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1004
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1005
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:848
TInterface::MPCPHostPortEditBox
TEdit * MPCPHostPortEditBox
Definition: InterfaceUnit.h:731
TTrainController::OtherMissedEvents
int OtherMissedEvents
Definition: TrainUnit.h:842
TUtilities::ReadOneLineFromCouplingFile
bool ReadOneLineFromCouplingFile(std::ifstream &InFile, AnsiString &OutString)
reads a single line from the multiplayer coupling file, returns true for success with OutString conta...
Definition: Utilities.cpp:618
TInterface::MoveTextOrGraphicButton
TBitBtn * MoveTextOrGraphicButton
Definition: InterfaceUnit.h:102
TTrainDataEntry::Description
AnsiString Description
headcode is the first train's headcode, rest are calculated from repeat information; ServiceReference...
Definition: TrainUnit.h:209
TInterface::RouteContinuing
@ RouteContinuing
Definition: InterfaceUnit.h:1024
TTrainController::EarlyExits
int EarlyExits
Definition: TrainUnit.h:831
TTrain::ExitSpeedHalf
double ExitSpeedHalf
speed when half way into the next element
Definition: TrainUnit.h:420
SignalPost
@ SignalPost
Definition: TrackUnit.h:65
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9499
TTrain::LastActionTime
TDateTime LastActionTime
time of the last timetabled event, used to ensure at least a 30 second delay before the next action
Definition: TrainUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17708
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:502
TInterface::InfoPanel
TPanel * InfoPanel
the general information panel (with blue 'i' symbol)
Definition: InterfaceUnit.h:409
TInterface::TServiceInfo::CheckOK
bool CheckOK()
Definition: InterfaceUnit.cpp:25384
TInterface::TextOrUserGraphicGridButtonClick
void __fastcall TextOrUserGraphicGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1810
TInterface::FormKeyDown
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13221
TInterface::MoveTTEntryDownButton
TButton * MoveTTEntryDownButton
Definition: InterfaceUnit.h:170
TInterface::CheckTimetableFromSessionFile
bool CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Check the timetable file embedded within a session file & return false for error, called during Sessi...
Definition: InterfaceUnit.cpp:20783
TInterface::SkipTTTrainMousePosY
int SkipTTTrainMousePosY
used to retain the mouse position on the train for SkipTimetabledActionsMenuItemClick
Definition: InterfaceUnit.h:1393
TRailGraphics::SpeedBut71GrndBlackGlyph
Graphics::TBitmap * SpeedBut71GrndBlackGlyph
Definition: GraphicUnit.h:1071
TInterface::DeleteTTEntryButtonClick
void __fastcall DeleteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3960
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7650
TTrainController::SecondPassActions
bool SecondPassActions(int Caller, bool GiveMessages, bool &TwoLocationFlag)
Carry out further detailed timetable consistency checks, return true for success.
Definition: TrainUnit.cpp:12239
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6828
TInterface::WarningFlashCount
int WarningFlashCount
increments each clock cycle to a max. of 4 then resets to 0, used to toggle bool WarningFlash - see a...
Definition: InterfaceUnit.h:1417
TInterface::StartWholeRailwayMoveHPos
int StartWholeRailwayMoveHPos
mouse X position when start to move the whole railway
Definition: InterfaceUnit.h:1395
TInterface::SpeedButton93
TSpeedButton * SpeedButton93
Definition: InterfaceUnit.h:635
TInterface::SpeedButton119
TSpeedButton * SpeedButton119
Definition: InterfaceUnit.h:661
TInterface::SelectedGraphicFileName
AnsiString SelectedGraphicFileName
filename for selected graphic set during LoadGraphic
Definition: InterfaceUnit.h:1210
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8823
TInterface::TrackBuildPanelLabel
TLabel * TrackBuildPanelLabel
label to the left of TrackBuildPanel
Definition: InterfaceUnit.h:352
clNormalBackground
#define clNormalBackground
Definition: GraphicUnit.h:297
TInterface::TTClockAdjButtonClick
void __fastcall TTClockAdjButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14306
TInterface::RAILWAY_DIR_NAME
static const UnicodeString RAILWAY_DIR_NAME
Definition: InterfaceUnit.h:997
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17693
TInterface::SPADImage
TImage * SPADImage
Definition: InterfaceUnit.h:299
TInterface::AddTrackButton
TBitBtn * AddTrackButton
Definition: InterfaceUnit.h:98
TInterface::MainMenu1
TMainMenu * MainMenu1
the program menu
Definition: InterfaceUnit.h:427
TInterface::OutputLog7MouseDown
void __fastcall OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13793
TInterface::LoadClipboard
void LoadClipboard(int Caller)
Load system clipboard to allow cutting & pasting between separate railway applications.
Definition: InterfaceUnit.cpp:22978
Concourse
@ Concourse
Definition: TrackUnit.h:66
TTextHandler::TTextVectorIterator
std::vector< TTextItem >::iterator TTextVectorIterator
Definition: TextUnit.h:66
TTrainController::SPADRisks
int SPADRisks
Definition: TrainUnit.h:845
TInterface::LocationNamesNotSetImage
TImage * LocationNamesNotSetImage
Definition: InterfaceUnit.h:316
TInterface::FloatingPanel
TPanel * FloatingPanel
new for v2.2.0 where label sits in it and it autosizes to the label. Labels are not TWinControls so t...
Definition: InterfaceUnit.h:419
TRailGraphics::SpeedBut68NormBlackGlyph
Graphics::TBitmap * SpeedBut68NormBlackGlyph
Definition: GraphicUnit.h:1060
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:801
TRailGraphics::SolidCircleYellow
Graphics::TBitmap * SolidCircleYellow
Definition: GraphicUnit.h:562
TInterface::SaveMenuItemClick
void __fastcall SaveMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2581
TInterface::ScreenGridButtonClick
void __fastcall ScreenGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1920
TTrain::EntrySpeed
double EntrySpeed
speed at which the train enters the next element
Definition: TrainUnit.h:418
TInterface::UserGraphicMoveHPos
int UserGraphicMoveHPos
Definition: InterfaceUnit.h:1415
TInterface::PassRedSignalMenuItemClick
void __fastcall PassRedSignalMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12838
TInterface::ReselectMenuItem
TMenuItem * ReselectMenuItem
Definition: InterfaceUnit.h:468
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13760
TInterface::MajorDelaysMenuItemClick
void __fastcall MajorDelaysMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:23489
TInterface::ClearEverything
bool ClearEverything(int Caller)
First check whether a railway file has changed and if so ask user if really wants to close it without...
Definition: InterfaceUnit.cpp:15752
TInterface::PrefDirContinuing
@ PrefDirContinuing
Definition: InterfaceUnit.h:1013
TTrain::TrainGone
bool TrainGone
set when train has left the railway, so it can be removed from the display at the next clock tick
Definition: TrainUnit.h:478
TRailGraphics::SpeedBut70NormBlackGlyph
Graphics::TBitmap * SpeedBut70NormBlackGlyph
Definition: GraphicUnit.h:1062
TTrainController::OnTimePasses
int OnTimePasses
Definition: TrainUnit.h:840
TInterface::SaveAsMenuItem
TMenuItem * SaveAsMenuItem
Definition: InterfaceUnit.h:448
TInterface::MoveTextOrGraphicButtonClick
void __fastcall MoveTextOrGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1075
TInterface::NumHVPairCheckOK
bool NumHVPairCheckOK(TNumHVPair NumHVPair)
check for datagram validity
Definition: InterfaceUnit.cpp:25365
TTrainController::SigSHigh
bool SigSHigh
Definition: TrainUnit.h:805
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4540
TInterface::ZoomButton
TBitBtn * ZoomButton
Definition: InterfaceUnit.h:290
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1878
TInterface::PrefDirConflictAdviceMessageSent
bool PrefDirConflictAdviceMessageSent
indicates that the advisory message drawing attention to the pref dir conflict checker has been given
Definition: InterfaceUnit.h:1259
TInterface::SkipTTTrainMousePosX
int SkipTTTrainMousePosX
Definition: InterfaceUnit.h:1392
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TInterface::CopyTTEntryButton
TButton * CopyTTEntryButton
Definition: InterfaceUnit.h:165
TInterface::ErrorMessageStoreImage
TMemo * ErrorMessageStoreImage
the text of the error message for failure to draw trains in SaveOperatingImage
Definition: InterfaceUnit.h:432
TInterface::SpeedButton76
TSpeedButton * SpeedButton76
Definition: InterfaceUnit.h:618
TTrain::StoppedAfterSPAD
bool StoppedAfterSPAD
Definition: TrainUnit.h:482
TInterface::SpeedButton145
TSpeedButton * SpeedButton145
Definition: InterfaceUnit.h:687
TInterface::NoPrefDirMode
@ NoPrefDirMode
Definition: InterfaceUnit.h:1013
TInterface::SpeedButton88
TSpeedButton * SpeedButton88
Definition: InterfaceUnit.h:630
TTrainController::OnTimeArrivals
int OnTimeArrivals
Definition: TrainUnit.h:838
TInterface::MoveTTEntryDownButtonClick
void __fastcall MoveTTEntryDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4477
TInterface::PerformanceLogBox
TMemo * PerformanceLogBox
the performance log displayed during operation
Definition: InterfaceUnit.h:436
TRailGraphics::SpeedBut72GrndBlackGlyph
Graphics::TBitmap * SpeedBut72GrndBlackGlyph
Definition: GraphicUnit.h:1072
TInterface::SpeedButton28
TSpeedButton * SpeedButton28
Definition: InterfaceUnit.h:570
TAllRoutes::LevelCrossingBarrierUpDelay
const float LevelCrossingBarrierUpDelay
the full value in seconds for which the level crossing flashes prior to closing to trains
Definition: TrackUnit.h:1680
TInterface::SpeedTopLabel
TLabel * SpeedTopLabel
Definition: InterfaceUnit.h:215
TInterface::OperateButton
TBitBtn * OperateButton
Definition: InterfaceUnit.h:229
clFrontCodeSignaller
#define clFrontCodeSignaller
Definition: GraphicUnit.h:295
TInterface::SignallerJoinedByMenuItemClick
void __fastcall SignallerJoinedByMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11992
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:766
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TActionVectorEntry::ArrivalTime
TDateTime ArrivalTime
Definition: TrainUnit.h:136
TTrain::StoppedAtBuffers
bool StoppedAtBuffers
Definition: TrainUnit.h:482
TInterface::SkipFormResizeEvent
bool SkipFormResizeEvent
added at v2.1.0 to avoid calling the event during startup and shutdown
Definition: InterfaceUnit.h:1287
TTrainController::CreateTTAnalysisFile
bool CreateTTAnalysisFile(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir, bool ArrChecked, bool DepChecked, bool AtLocChecked, bool DirChecked, int ArrRange, int DepRange)
Generate a timetable analysis file in the 'Formatted Timetables' folder, return false if failed for a...
Definition: TrainUnit.cpp:16517
TTrain::Mass
int Mass
in kg
Definition: TrainUnit.h:456
TInterface::TrackInfoOnOffMenuItem
TMenuItem * TrackInfoOnOffMenuItem
Definition: InterfaceUnit.h:483
TInterface::NumToIPAndPort
bool NumToIPAndPort(unsigned char RlyUserNumber, AnsiString &UserIP, short UserPort)
Definition: InterfaceUnit.cpp:25344
TDisplay::ShowWarningLog
void ShowWarningLog(int Caller)
Show the warnings after timetable clock adjusted.
Definition: DisplayUnit.cpp:568
TInterface::SpeedButton121
TSpeedButton * SpeedButton121
Definition: InterfaceUnit.h:663
TTrainController::ProcessOneTimetableLine
bool ProcessOneTimetableLine(int Caller, int Count, AnsiString OneLine, bool &EndOfFile, bool FinalCall, bool GiveMessages, bool CheckLocationsExistInRailway)
Carry out preliminary (mainly syntax) validity checks on a single timetable service entry and (if Fin...
Definition: TrainUnit.cpp:10496
TInterface::RLIt
TRailwayList::iterator RLIt
Definition: InterfaceUnit.h:1051
TInterface::SaveAsMenuItemClick
void __fastcall SaveAsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2634
TTextItem
A single piece of text that can be displayed on the railway.
Definition: TextUnit.h:36
TInterface::SpeedButton136
TSpeedButton * SpeedButton136
Definition: InterfaceUnit.h:678
TInterface::PointFlash
TGraphicElement * PointFlash
Definition: InterfaceUnit.h:1430
TInterface::MPCPLabel8
TLabel * MPCPLabel8
Definition: InterfaceUnit.h:735
TInterface::TrackLinkedImage
TImage * TrackLinkedImage
Definition: InterfaceUnit.h:311
TTrain::LeadExitPos
int LeadExitPos
Definition: TrainUnit.h:366
TInterface::MPCPReadyToBeginButton
TButton * MPCPReadyToBeginButton
Definition: InterfaceUnit.h:717
TInterface::SelectPickedUp
bool SelectPickedUp
true when a valid selected screen area has been clicked after a 'Copy' or 'Cut' selected in the 'Edit...
Definition: InterfaceUnit.h:1281
TDisplay::ResetZoomOutOffsets
void ResetZoomOutOffsets()
Reset the zoomed-out screen display to the 'Home' position.
Definition: DisplayUnit.h:209
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:157
TInterface::DevelopmentPanel
TPanel * DevelopmentPanel
used for diagnostic purposes, made visible by ctrl+ alt+ 3
Definition: InterfaceUnit.h:417
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1897
TTrain::SkipPtrValue
int SkipPtrValue
stores the pointer increment from first action in ActionVector for skipped actions when a departure i...
Definition: TrainUnit.h:374
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:774
TInterface::PerformancePanel
TPanel * PerformancePanel
displays the operating performance log
Definition: InterfaceUnit.h:411
TTrainController::DerailWarning
bool DerailWarning
Definition: TrainUnit.h:791
TInterface::CopyMoving
@ CopyMoving
Definition: InterfaceUnit.h:1019
TInterface::TimetableEditPanel
TPanel * TimetableEditPanel
the large panel that contains all the main timetable components
Definition: InterfaceUnit.h:403
TInterface::RouteMode
enum TInterface::@0 RouteMode
route building modes
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TInterface::TrainStatusInfoOnOffMenuItem
TMenuItem * TrainStatusInfoOnOffMenuItem
Definition: InterfaceUnit.h:485
TInterface::SetLengthsButtonClick
void __fastcall SetLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1362
TInterface::SaveTTEntryButton
TButton * SaveTTEntryButton
Definition: InterfaceUnit.h:171
TInterface::SpeedButton37
TSpeedButton * SpeedButton37
Definition: InterfaceUnit.h:579
TInterface::BaseMode
@ BaseMode
Definition: InterfaceUnit.h:986
TInterface::SpeedEditBoxKeyUp
void __fastcall SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13997
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:652
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11260
TInterface::MirrorMenuItem
TMenuItem * MirrorMenuItem
Definition: InterfaceUnit.h:472
TInterface::EveryPrefDir
TOnePrefDir * EveryPrefDir
all the Pref Dir elements in the railway
Definition: InterfaceUnit.h:1441
TTrainController::TotLateDepMins
float TotLateDepMins
Definition: TrainUnit.h:822
TDisplay::ZoomOutFlag
bool ZoomOutFlag
true when zoomed-out
Definition: DisplayUnit.h:70
TInterface::TServiceInfo
Definition: InterfaceUnit.h:1076
TInterface::OutputLog8
TLabel * OutputLog8
Definition: InterfaceUnit.h:336
TInterface::SpeedButton1
TSpeedButton * SpeedButton1
See Speedbutton1 detail for track element allocations.
Definition: InterfaceUnit.h:543
TInterface::MinorDelaysMenuItem
TMenuItem * MinorDelaysMenuItem
Definition: InterfaceUnit.h:753
TTrainController::TrainVector
TTrainVector TrainVector
vector containing all trains currently in the railway
Definition: TrainUnit.h:876
TInterface::SaveAsSubroutine
void SaveAsSubroutine(int Caller)
Used to save a railway when not already saved - e.g. when not already named or when the 'Save as' men...
Definition: InterfaceUnit.cpp:22313
TInterface::DynMapFromHost
TDynamicMap DynMapFromHost
Definition: InterfaceUnit.h:1103
TInterface::MainScreenMouseDown2
void MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-in mode.
Definition: InterfaceUnit.cpp:5937
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1526
TInterface::RepairFailedTrainMenuItemClick
void __fastcall RepairFailedTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12088
TInterface::AddLocationName
@ AddLocationName
Definition: InterfaceUnit.h:1018
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8620
TInterface::MPHPOwnIPEditBox
TEdit * MPHPOwnIPEditBox
Definition: InterfaceUnit.h:739
TTrack::IsTrackFinished
bool IsTrackFinished()
Indicates whether or not the track has been successfully linked together.
Definition: TrackUnit.h:823
TAllRoutes::AllRoutesClear
void AllRoutesClear()
Erases all routes from AllRoutesVector and from Route2MultiMap.
Definition: TrackUnit.h:1708
TRailGraphics::SpeedBut74GrndBlackGlyph
Graphics::TBitmap * SpeedBut74GrndBlackGlyph
Definition: GraphicUnit.h:1074
TInterface::ShowTTActionsListBox
void ShowTTActionsListBox(int Caller)
makes TTActionsListBox visible and stops the tt clock
Definition: InterfaceUnit.cpp:12444
TAllRoutes::PointsDelay
const float PointsDelay
the value in seconds for which points flash prior to being changed. Used for the points flash period ...
Definition: TrackUnit.h:1684
TInterface::SaveSession
void SaveSession(int Caller)
Save a session file - see LoadSession for details of additions to the session file.
Definition: InterfaceUnit.cpp:19527
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5738
TUtilities::CallLogPop
void CallLogPop(int Caller)
< specifies whether no delays or minor, moderate or major random delays are to be applied
Definition: Utilities.cpp:50
TAllRoutes::SignalsDelay
const float SignalsDelay
the value in seconds for which signals flash prior to being changed. Used for the route flash period ...
Definition: TrackUnit.h:1686
TDisplay::GetFont
TFont * GetFont()
Return the current screen font.
Definition: DisplayUnit.h:133
TInterface::SpeedButton10
TSpeedButton * SpeedButton10
Definition: InterfaceUnit.h:552
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:317
TInterface::SpeedButton103
TSpeedButton * SpeedButton103
Definition: InterfaceUnit.h:645
TInterface::SaveMultiplayerSessionMenuItem
TMenuItem * SaveMultiplayerSessionMenuItem
Definition: InterfaceUnit.h:709
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1300
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:848
TTrainController::TotEarlyArrMins
float TotEarlyArrMins
values for performance file summary
Definition: TrainUnit.h:817
TInterface::PerformancePanelStartDrag
void __fastcall PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5856
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13131
TInterface::TempCursorSet
bool TempCursorSet
indicates that a screen cursor has been stored in TempCursor for redisplay after a temporary cursor (...
Definition: InterfaceUnit.h:1289
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12266
TInterface::SpeedButton85
TSpeedButton * SpeedButton85
Definition: InterfaceUnit.h:627
TInterface::PasteMenuItemClick
void __fastcall PasteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10799
TInterface::MPCPLabel6
TLabel * MPCPLabel6
Definition: InterfaceUnit.h:729
TInterface::MainScreenMouseUp
void __fastcall MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7932
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TInterface::SaveTempTimetableFile
void SaveTempTimetableFile(int Caller, AnsiString InFileName)
Save a timetable as a temporary file either on loading directly or on loading a session file....
Definition: InterfaceUnit.cpp:22064
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1690
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TInterface::RotateMenuItemClick
void __fastcall RotateMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10088
TTrainDataEntry::SignallerSpeed
int SignallerSpeed
in km/h for use when under signaller control
Definition: TrainUnit.h:221
TInterface::OverallDistance
int OverallDistance
Definition: InterfaceUnit.h:1374
TInterface::SelectStartPair
THVShortPair SelectStartPair
'Select' menu items
Definition: InterfaceUnit.h:1432
TInterface::SpeedButton105
TSpeedButton * SpeedButton105
Definition: InterfaceUnit.h:647
TInterface::SpeedButton83
TSpeedButton * SpeedButton83
Definition: InterfaceUnit.h:625
TTrain::AbleToMove
bool AbleToMove(int Caller)
Indicates that a train is not prevented from moving - used to allow appropriate popup menu options wh...
Definition: TrainUnit.cpp:6972
TTrainController::MTBFHours
double MTBFHours
Mean time between failures in timetable clock hours.
Definition: TrainUnit.h:808
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12759
TInterface::RestoreAllDefaultLengthsButtonClick
void __fastcall RestoreAllDefaultLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1719
TInterface::LengthWarningSentFlag
bool LengthWarningSentFlag
indicates that the length selection applying to all elements in the selection warning has been given,...
Definition: InterfaceUnit.h:1241
TInterface::SpeedButton131
TSpeedButton * SpeedButton131
Definition: InterfaceUnit.h:673
TInterface::FlipMenuItemClick
void __fastcall FlipMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9849
TInterface::api_main_mode_
int api_main_mode_
Definition: InterfaceUnit.h:1170
TInterface::TrainTTInfoOnOffMenuItem
TMenuItem * TrainTTInfoOnOffMenuItem
Definition: InterfaceUnit.h:486
TInterface::AllSetUpFlag
bool AllSetUpFlag
false during initial start up, true when all set up to allow MasterClock to start
Definition: InterfaceUnit.h:1213
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3639
TInterface::LocationNameButton
TBitBtn * LocationNameButton
Definition: InterfaceUnit.h:103
TInterface::SpeedButton101
TSpeedButton * SpeedButton101
Definition: InterfaceUnit.h:643
TTrain::TrainMode
TTrainMode TrainMode
mode of operation - either Timetable (running under timetable control) or Signaller (running under si...
Definition: TrainUnit.h:470
TInterface::BuildDummyTestMap
void BuildDummyTestMap(TDynamicMap &DMap, std::ifstream &ExitFile)
Definition: InterfaceUnit.cpp:25117
TInterface::LoadRailway
void LoadRailway(int Caller, AnsiString LoadFileName)
Load a railway file. The Active elements marker now has a '1' at the end if there are user graphics t...
Definition: InterfaceUnit.cpp:2428
TInterface::TAnsiCouplingPair
std::pair< AnsiString, THVShortPair > TAnsiCouplingPair
Definition: InterfaceUnit.h:1031
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11303
TInterface::RailwayList
TRailwayList RailwayList
Definition: InterfaceUnit.h:1052
TInterface::TextOrUserGraphicGridButton
TBitBtn * TextOrUserGraphicGridButton
Definition: InterfaceUnit.h:105
TInterface::PointFlashVectorPosition
int PointFlashVectorPosition
Definition: InterfaceUnit.h:1381
TInterface::AddSubMinsBoxKeyUp
void __fastcall AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4815
TInterface::ExitOperationButtonClick
void __fastcall ExitOperationButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2329
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1780
TInterface::TTClockAdd1hButtonClick
void __fastcall TTClockAdd1hButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14554
TUtilities::Format96HHMM
AnsiString Format96HHMM(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm where hh runs from 00 to 95 & resets when it...
Definition: Utilities.cpp:807
TInterface::TTClockx2ButtonClick
void __fastcall TTClockx2ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14382
TInterface::PerformancePanelDragStartX
int PerformancePanelDragStartX
mouse 'X' position when the performance panel begins to be dragged
Definition: InterfaceUnit.h:1377
TInterface::SpeedButton45
TSpeedButton * SpeedButton45
Definition: InterfaceUnit.h:587
TInterface::SpeedEditBox2KeyUp
void __fastcall SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:14153
TInterface::SavedFileName
AnsiString SavedFileName
the full path and filename of the loaded railway
Definition: InterfaceUnit.h:1204
TInterface::FillSelectionMessageSentFlag
bool FillSelectionMessageSentFlag
indicates that the message about filling a selected area with a chosen track element has been given,...
Definition: InterfaceUnit.h:1237
TInterface::PlanPrefDirsMenuItemClick
void __fastcall PlanPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1947
TInterface::OperatingPanel
TPanel * OperatingPanel
'Operate railway' panel
Definition: InterfaceUnit.h:400
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:913
TInterface::SpeedButton141
TSpeedButton * SpeedButton141
Definition: InterfaceUnit.h:683
TInterface::ShowOperatorActionPanel
bool ShowOperatorActionPanel
true when the 'trains needing action' button has been clicked during operation (new at v2....
Definition: InterfaceUnit.h:1309
TInterface::TServiceInfo::TimeToExitSecs
short TimeToExitSecs
Definition: InterfaceUnit.h:1080
TTrack::GetGapVLoc
int GetGapVLoc()
Definition: TrackUnit.h:857
TInterface::SpeedButton124
TSpeedButton * SpeedButton124
Definition: InterfaceUnit.h:666
TUtilities::CheckFileString
bool CheckFileString(std::ifstream &InFile)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success
Definition: Utilities.cpp:399
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12579
TRailGraphics::bmGrid
Graphics::TBitmap * bmGrid
Definition: GraphicUnit.h:522
TInterface::RestoreFocusPanel
TPanel * RestoreFocusPanel
Panel used to restore focus to Interface to enable cursor keys to move screen.
Definition: InterfaceUnit.h:391
TInterface::BlackBgndMenuItem
TMenuItem * BlackBgndMenuItem
Definition: InterfaceUnit.h:463
SignallerControlStop
@ SignallerControlStop
Definition: TrainUnit.h:54
TInterface::DynMapToHost
TDynamicMap DynMapToHost
Definition: InterfaceUnit.h:1103
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:801
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:622
TInterface::FloatingLabel
TLabel * FloatingLabel
the floating window that displays track & train information
Definition: InterfaceUnit.h:372
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11454
TInterface::NewTTEntryButton
TButton * NewTTEntryButton
Definition: InterfaceUnit.h:173
TTrainController::ExcessLCDownMins
float ExcessLCDownMins
total excess time in minutes over the 3 minutes barriers down allowance for level crossings
Definition: TrainUnit.h:815
TInterface::SubMinsButtonClick
void __fastcall SubMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3707
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:427
TInterface::TimetableControlMenuItemClick
void __fastcall TimetableControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11751
TInterface::MPCPLabel4
TLabel * MPCPLabel4
Definition: InterfaceUnit.h:718
TTrack::TActiveTrackElementNameIterator
TActiveTrackElementNameMap::iterator TActiveTrackElementNameIterator
Definition: TrackUnit.h:701
TInterface::DistanceBox
TEdit * DistanceBox
distance/speed setting edit box that accepts distances
Definition: InterfaceUnit.h:125
TInterface::SpeedButton142
TSpeedButton * SpeedButton142
Definition: InterfaceUnit.h:684
TInterface::PresetAutoSigRoutesButton
TBitBtn * PresetAutoSigRoutesButton
Definition: InterfaceUnit.h:234
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:134
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TInterface::TTLabel12
TLabel * TTLabel12
Definition: InterfaceUnit.h:386
TInterface::TTServiceSyntaxCheckButtonClick
void __fastcall TTServiceSyntaxCheckButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4323
TInterface::SpeedButton57
TSpeedButton * SpeedButton57
Definition: InterfaceUnit.h:599
TInterface::TAnsiCouplingMapEntry
std::pair< TAnsiCouplingPair, TAnsiCouplingPair > TAnsiCouplingMapEntry
TAnsiCouplingMap... items are just used temporarily to load the CouplingFile into a RailwayName based...
Definition: InterfaceUnit.h:1032
TInterface::TTClockSpeed
float TTClockSpeed
rate at which the timetable clock runs 1 = normal
Definition: InterfaceUnit.h:1351
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TDisplay::PlotAbsolute
void PlotAbsolute(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Definition: DisplayUnit.cpp:489
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5786
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1814
TInterface::TTClockx4ButtonClick
void __fastcall TTClockx4ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14401
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13698
TTextHandler::TextFound
bool TextFound(int Caller, int HPosInput, int VPosInput, AnsiString &Text)
look for a text item in the vicinity of HPosInput & VPosInput, return true if found & return the foun...
Definition: TextUnit.cpp:240
TInterface::LCManualLowerBarriersMessageSent
bool LCManualLowerBarriersMessageSent
indicates that the manual LC operation message has been given, so it won't be given again
Definition: InterfaceUnit.h:1239
TInterface::SaveImageAndPrefDirsMenuItemClick
void __fastcall SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2840
TInterface::AddMinsButton
TButton * AddMinsButton
Definition: InterfaceUnit.h:176
SignallerStepForward
@ SignallerStepForward
Definition: TrainUnit.h:54
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:867
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TInterface::MultiplayerRailwayValid
bool MultiplayerRailwayValid(AnsiString RailwayName, char &ErrorNumber)
checks whether a railway loaded by a player is listed and available
Definition: InterfaceUnit.cpp:24134
TInterface::SpeedButton60
TSpeedButton * SpeedButton60
Definition: InterfaceUnit.h:602
TInterface::TrackInfoOnOffMenuItemClick
void __fastcall TrackInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5710
TInterface::RecoverClipboard
void RecoverClipboard(int Caller, bool &ValidResult)
Recovers clipboard as track and text vectors.
Definition: InterfaceUnit.cpp:23192
TInterface::JoinMultiplayerSessionMenuItem
TMenuItem * JoinMultiplayerSessionMenuItem
Definition: InterfaceUnit.h:710
TTrainController::LateExits
int LateExits
Definition: TrainUnit.h:836
TTrainController::OpTimeToActUpdateCounter
unsigned int OpTimeToActUpdateCounter
<List of all ServiceRefs that have two or more same locations without a cdt between - loaded during S...
Definition: TrainUnit.h:860
TTrain::BeingCalledOn
bool BeingCalledOn
in course of being called on to a station
Definition: TrainUnit.h:380
TInterface::MPHPStartButtonClick
void __fastcall MPHPStartButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:23689
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TInterface::AZOrderButtonClick
void __fastcall AZOrderButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5221
TInterface::CopySelected
bool CopySelected
used to indicate whether copy or cut selected in edit menu - for clipboard pasting
Definition: InterfaceUnit.h:1225
TInterface::HiddenScreen
TImage * HiddenScreen
a hidden copy of the railway display screen used during ClearandRebuildRailway (see below) to avoid f...
Definition: InterfaceUnit.h:1436
TInterface::PerformancePanelLabelStartDrag
void __fastcall PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:13128
TTrain::CalcTimeToAct
float CalcTimeToAct(int Caller, float &TimeToExit, THVShortPair &ExitPair)
new v2.2.0 for operator action panel. Calculates the time left for operator action to avoid unnecessa...
Definition: TrainUnit.cpp:8734
TInterface::LoadPerformanceFile
void LoadPerformanceFile(int Caller, std::ifstream &InFile)
Load the performance file part of a sessionfile.
Definition: InterfaceUnit.cpp:21574
TInterface::MPCPPlayerNameEditBox
TEdit * MPCPPlayerNameEditBox
Definition: InterfaceUnit.h:715
TInterface::CPCancelButtonClick
void __fastcall CPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:15086
TInterface::OutputLog4MouseDown
void __fastcall OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13764
TInterface::AddGraphic
@ AddGraphic
Definition: InterfaceUnit.h:1018
TInterface::SetLevel1Mode
void SetLevel1Mode(int Caller)
Sets the Level1 user mode, using the Level1Mode variable to determine the mode.
Definition: InterfaceUnit.cpp:15999
TInterface::NewHomeButtonClick
void __fastcall NewHomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9671
TInterface::OutputLog4
TLabel * OutputLog4
Definition: InterfaceUnit.h:332
TInterface::FontDialog
TFontDialog * FontDialog
font change dialog
Definition: InterfaceUnit.h:534
TInterface::MPHPStartButton
TButton * MPHPStartButton
Definition: InterfaceUnit.h:726
TInterface::TwoLocationNamePanelHide
bool TwoLocationNamePanelHide
true if user opts not to show the two location name warning (false on starting the program)
Definition: InterfaceUnit.h:1295
TInterface::TrackSelecting
@ TrackSelecting
Definition: InterfaceUnit.h:1019
TTrainController::TotLateArrMins
float TotLateArrMins
Definition: TrainUnit.h:821
TInterface::Level2PrefDirMode
enum TInterface::TLevel2PrefDirMode Level2PrefDirMode
TInterface::OperatingPanelLabel
TLabel * OperatingPanelLabel
displays 'Operation' or 'Disabled' on the operating panel during operation for running or paused
Definition: InterfaceUnit.h:360
TInterface::DivergingPointVectorPosition
int DivergingPointVectorPosition
Definition: InterfaceUnit.h:1381
TInterface::OAListBoxMouseUp
void __fastcall OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4909
TTrainController::PlotAllTrainsInZoomOutMode
void PlotAllTrainsInZoomOutMode(int Caller, bool Flash)
Plots all trains on screen in zoomed-out mode, state of 'Flash' determines whether the flashing train...
Definition: TrainUnit.cpp:15873
TInterface::SpeedButton108
TSpeedButton * SpeedButton108
Definition: InterfaceUnit.h:650
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1476
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8587
TInterface::SavePerformanceFile
void SavePerformanceFile(int Caller, std::ofstream &OutFile)
Save performance file part of a session file.
Definition: InterfaceUnit.cpp:21638
TTextItem::Font
TFont * Font
the text font
Definition: TextUnit.h:52
TInterface::MPCPPlayerNameEditBoxKeyUp
void __fastcall MPCPPlayerNameEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:24790
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1631
TTrain::SignallerStopped
bool SignallerStopped
Definition: TrainUnit.h:482
API::dump
void dump()
save currently recorded status data to INI file
Definition: API.cpp:37
TInterface::MPHPOwnPortEditBox
TEdit * MPHPOwnPortEditBox
Definition: InterfaceUnit.h:737
TDisplay::SetFont
void SetFont(TFont *Font)
Set the screen font to 'Font'.
Definition: DisplayUnit.h:216
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17547
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1620
TTrain::TrainDataEntryPtr
TTrainDataEntry * TrainDataEntryPtr
points to the current position in the timetable's TrainDataVector
Definition: TrainUnit.h:370
TInterface::TTLabel13
TLabel * TTLabel13
Definition: InterfaceUnit.h:387
TTrainDataEntry::StartSpeed
int StartSpeed
in km/h
Definition: TrainUnit.h:223
TTrainDataEntry::NumberOfTrains
int NumberOfTrains
number of repeats + 1
Definition: TrainUnit.h:219
TTrainController::Derailments
int Derailments
Definition: TrainUnit.h:828
clStationStopBackground
#define clStationStopBackground
Definition: GraphicUnit.h:301
TUtilities::CumulativeDelayedRandMinsAllTrains
int CumulativeDelayedRandMinsAllTrains
Definition: Utilities.h:57
TInterface::AZOrderButton
TButton * AZOrderButton
Definition: InterfaceUnit.h:175
TInterface::SpeedButton86
TSpeedButton * SpeedButton86
Definition: InterfaceUnit.h:628
TInterface::SpeedButton122
TSpeedButton * SpeedButton122
Definition: InterfaceUnit.h:664
Crossover
@ Crossover
Definition: TrackUnit.h:65
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6286
TInterface::SpeedButton104
TSpeedButton * SpeedButton104
Definition: InterfaceUnit.h:646
TInterface::SignallerJoinedByMenuItem
TMenuItem * SignallerJoinedByMenuItem
Definition: InterfaceUnit.h:516
TRailGraphics::SpeedBut69NormBlackGlyph
Graphics::TBitmap * SpeedBut69NormBlackGlyph
Definition: GraphicUnit.h:1061
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7291
TDisplay::ResetZoomInOffsets
void ResetZoomInOffsets()
Reset the zoomed-in screen display to the 'Home' position.
Definition: DisplayUnit.h:202
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9962
TInterface::RotRightMenuItem
TMenuItem * RotRightMenuItem
Definition: InterfaceUnit.h:514
AtLocation
@ AtLocation
Definition: TrainUnit.h:72
TInterface::ExportTTButton
TButton * ExportTTButton
Definition: InterfaceUnit.h:183
Signal
@ Signal
Definition: TrackUnit.h:75
TPrefDirElement::GetSignedIntTrackVectorPosition
int GetSignedIntTrackVectorPosition() const
Returns signed integer value of TrackVectorPosition (used in flip, mirror etc for pref dirs) added at...
Definition: TrackUnit.h:305
TInterface::TimetableChangedFlag
bool TimetableChangedFlag
true when a timetable in the editor has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:1303
TInterface::SaveTimetableToErrorFile
bool SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
Called when compiling the error log file, to save the loaded timetable if any and the timetable being...
Definition: InterfaceUnit.cpp:20576
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:772
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17997
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:152
TInterface::TrainHeadCodeMenuItem
TMenuItem * TrainHeadCodeMenuItem
Definition: InterfaceUnit.h:497
TTrainController::TrainDataVector
TTrainDataVector TrainDataVector
vector containing the internal timetable
Definition: TrainUnit.h:874
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12629
TAllRoutes::NotAutoSigsRoute
@ NotAutoSigsRoute
Definition: TrackUnit.h:1621
TTrain::ExitTimeHalf
TDateTime ExitTimeHalf
Definition: TrainUnit.h:462
TPrefDirElement::SetEntryDirectionGraphicPtr
void SetEntryDirectionGraphicPtr(Graphics::TBitmap *input)
Used in pasting pref dirs.
Definition: TrackUnit.h:370
Exited
@ Exited
Definition: TrainUnit.h:88
TInterface::OutputLog2
TLabel * OutputLog2
Definition: InterfaceUnit.h:330
TInterface::TTClockAdjustWarningLabel
TLabel * TTClockAdjustWarningLabel
Definition: InterfaceUnit.h:265
TInterface::SpeedButton74
TSpeedButton * SpeedButton74
Definition: InterfaceUnit.h:616
TInterface::ScreenRightButtonClick
void __fastcall ScreenRightButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9294
TInterface::TServiceInfo::ServiceReference
AnsiString ServiceReference
Definition: InterfaceUnit.h:1078
TInterface::PositionalPanel
TPanel * PositionalPanel
Definition: InterfaceUnit.h:421
TInterface::StepForwardMenuItemClick
void __fastcall StepForwardMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12881
TInterface::TRlyUserInfo::RailwayName
AnsiString RailwayName
Definition: InterfaceUnit.h:1058
TInterface::ErrorLog
void ErrorLog(int Caller, AnsiString Message)
The error logging routine, called when an error is detected.
Definition: InterfaceUnit.cpp:19176
TInterface::SpeedButton50
TSpeedButton * SpeedButton50
Definition: InterfaceUnit.h:592
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10523
TTrain::ActionsSkippedFlag
bool ActionsSkippedFlag
prevents any further skipping until after the next departure
Definition: TrainUnit.h:329
TTrainController::LoadSessionTrains
void LoadSessionTrains(int Caller, std::ifstream &SessionFile)
load trains from a session file
Definition: TrainUnit.cpp:15571
TInterface::NoDelaysMenuItem
TMenuItem * NoDelaysMenuItem
Definition: InterfaceUnit.h:752
TInterface::ConvertIDToPair
bool ConvertIDToPair(AnsiString HVID, THVShortPair &HVPair)
Definition: InterfaceUnit.cpp:24077
TInterface::SpeedButton31
TSpeedButton * SpeedButton31
Definition: InterfaceUnit.h:573
TInterface::UserGraphicFoundFlag
bool UserGraphicFoundFlag
indicates that a user graphic item has been found when clicking on a build screen for moving
Definition: InterfaceUnit.h:1301
TRailGraphics::CouplingExit8
Graphics::TBitmap * CouplingExit8
Definition: GraphicUnit.h:558
TInterface::RouteCancelButtonClick
void __fastcall RouteCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2280
TInterface::SpeedButton91
TSpeedButton * SpeedButton91
Definition: InterfaceUnit.h:633
TUtilities::CheckAndReadOneLineFromConfigFile
bool CheckAndReadOneLineFromConfigFile(std::ifstream &InFile, AnsiString &OutString)
similar to CheckAndReadFileString but allows tab characters and doesn't ignore initial characters
Definition: Utilities.cpp:581
TInterface::SelectedTrainID
int SelectedTrainID
used to store the train ID when right clicked for signaller control actions
Definition: InterfaceUnit.h:1390
TInterface::SpeedButton113
TSpeedButton * SpeedButton113
Definition: InterfaceUnit.h:655
TInterface::SpeedButton82
TSpeedButton * SpeedButton82
Definition: InterfaceUnit.h:624
TInterface::MultiplayerHostSessionMenuItemClick
void __fastcall MultiplayerHostSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:23508
TTextHandler::SelectTextPtrAt
TTextItem * SelectTextPtrAt(int Caller, int At)
return the text item at position 'At' in SelectTextVector (carries out range checking)
Definition: TextUnit.cpp:570
TInterface::SpeedButton132
TSpeedButton * SpeedButton132
Definition: InterfaceUnit.h:674
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:778
TInterface::FlashingGraphics
void FlashingGraphics(int Caller, TDateTime Now)
Deal with any warning graphics that need to flash (call on, signal stop, crash etc),...
Definition: InterfaceUnit.cpp:18541
TInterface::ScreenLeftButton
TBitBtn * ScreenLeftButton
Definition: InterfaceUnit.h:285
TInterface::CheckPrefDirConflictsMenuItem
TMenuItem * CheckPrefDirConflictsMenuItem
Definition: InterfaceUnit.h:479
TTrain::StoppedAtLocation
bool StoppedAtLocation
Definition: TrainUnit.h:482
TTrainController::TContinuationTrainExpectationMultiMapIterator
TContinuationTrainExpectationMultiMap::iterator TContinuationTrainExpectationMultiMapIterator
iterator for the multimap
Definition: TrainUnit.h:751
TInterface::TTClockx16ButtonClick
void __fastcall TTClockx16ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14439
TInterface::OAListBoxMouseDown
void __fastcall OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5003
TInterface::BuildTrackMenuItem
TMenuItem * BuildTrackMenuItem
Definition: InterfaceUnit.h:457
TInterface::SaveOperatingImageMenuItem
TMenuItem * SaveOperatingImageMenuItem
Definition: InterfaceUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:793
TInterface::NoRailway
bool NoRailway()
Returns true if there are no track elements and no text.
Definition: InterfaceUnit.cpp:22546
TInterface::AllEntriesTTListBox
TListBox * AllEntriesTTListBox
the list of service entries displayed on the left hand side of the timetable edit screen
Definition: InterfaceUnit.h:441
TInterface::MultiplayerHostStringGrid
TStringGrid * MultiplayerHostStringGrid
Definition: InterfaceUnit.h:732
TInterface::CallingOnButtonClick
void __fastcall CallingOnButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9202
TInterface::SaveTTDialog
TSaveDialog * SaveTTDialog
Definition: InterfaceUnit.h:533
TInterface::DeleteOnePrefDirButtonClick
void __fastcall DeleteOnePrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2024
TAllRoutes::NextRouteID
int NextRouteID
stores the value for the route ID number that is next to be built
Definition: TrackUnit.h:1688
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TInterface::TTEntryChangedFlag
bool TTEntryChangedFlag
true when a timetable entry that is displayed in the timetable entry edit window has changed
Definition: InterfaceUnit.h:1311
TInterface::HighlightPanel
TPanel * HighlightPanel
the orange bar that displays the current timetable entry in AllEntriesTTListBox
Definition: InterfaceUnit.h:407
TInterface::SpeedButton16
TSpeedButton * SpeedButton16
Definition: InterfaceUnit.h:558
TInterface::MoveTTEntryUpButtonClick
void __fastcall MoveTTEntryUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4415
TInterface::SpeedBottomLabel
TLabel * SpeedBottomLabel
Definition: InterfaceUnit.h:216
TInterface::CheckPrefDirConflictsMenuItemClick
void __fastcall CheckPrefDirConflictsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10973
TTrainController::BFHigh
bool BFHigh
Definition: TrainUnit.h:805
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TInterface::TTClockResetButtonClick
void __fastcall TTClockResetButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14614
TInterface::ClockLabel
TLabel * ClockLabel
the timetable clock
Definition: InterfaceUnit.h:358
TInterface::SpeedButton43
TSpeedButton * SpeedButton43
Definition: InterfaceUnit.h:585
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14528
TTrain::LagEntryPos
int LagEntryPos
Definition: TrainUnit.h:366
TInterface::SetTrackBuildImages
void SetTrackBuildImages(int Caller)
Sets the left screen images (track linked or not, gaps set or not, locations named or not) during rai...
Definition: InterfaceUnit.cpp:19428
TTrain::NewDelay
double NewDelay
< the remaining random delay at any point in time for the train
Definition: TrainUnit.h:438
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4141
TInterface::AddText
@ AddText
Definition: InterfaceUnit.h:1018
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2359
TTrainController::UnexpectedExits
int UnexpectedExits
Definition: TrainUnit.h:847
TInterface::LoadTimetableMenuItemClick
void __fastcall LoadTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11615
TInterface::LengthEditKeyUp
void __fastcall LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:14221
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12397
TInterface::OutputLog1
TLabel * OutputLog1
Definition: InterfaceUnit.h:329
TInterface::PopulateCouplingMap
bool PopulateCouplingMap(AnsiString FileName, int &NumExt)
Read couplingfile and convert into CouplingMap.
Definition: InterfaceUnit.cpp:23891
TTrain::LeavingUnderSigControlAtContinuation
bool LeavingUnderSigControlAtContinuation
set when the train has reached an exit continuation when under signaller control, used to prevent the...
Definition: TrainUnit.h:394
TInterface::TServiceInfo::RepeatNumber
short RepeatNumber
Definition: InterfaceUnit.h:1079
TInterface::SpeedButton84
TSpeedButton * SpeedButton84
Definition: InterfaceUnit.h:626
TInterface::SpeedButton77
TSpeedButton * SpeedButton77
Definition: InterfaceUnit.h:619
TInterface::SpeedButton128
TSpeedButton * SpeedButton128
Definition: InterfaceUnit.h:670
TInterface::GetTrainFloatingInfoFromContinuation
void GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat, AnsiString &TrainTTFloat)
Called when floating train info needed and train hasn't entered yet.
Definition: InterfaceUnit.cpp:18152
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:940
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5762
TInterface::AddSubMinsBox
TEdit * AddSubMinsBox
the edit box that accepts minutes to add or subtract
Definition: InterfaceUnit.h:210
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:19198
TInterface::TTClockExitButton
TButton * TTClockExitButton
Definition: InterfaceUnit.h:253
TInterface::SpeedEditBox2
TEdit * SpeedEditBox2
Definition: InterfaceUnit.h:136
API::add_metadata_int
void add_metadata_int(const AnsiString &label, int *data)
add pointer to integer variable to monitor value
Definition: API.cpp:32
TInterface::MoveForwardsMenuItemClick
void __fastcall MoveForwardsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11933
TTrack::Down
@ Down
Definition: TrackUnit.h:607
TTrainController::TwoOrMoreLocationsWarningGiven
bool TwoOrMoreLocationsWarningGiven
new at v2.6.0 to allow loops
Definition: TrainUnit.h:801
TInterface::TimetableNameLabel
TLabel * TimetableNameLabel
displays the current timetable name on the timetable edit panel
Definition: InterfaceUnit.h:348
TInterface::SpeedButton79
TSpeedButton * SpeedButton79
Definition: InterfaceUnit.h:621
TInterface::SpeedBottomLabel2
TLabel * SpeedBottomLabel2
Definition: InterfaceUnit.h:147
TInterface::SpeedButton51
TSpeedButton * SpeedButton51
Definition: InterfaceUnit.h:593
TInterface::IsPerformancePanelObscuringFloatingLabel
bool IsPerformancePanelObscuringFloatingLabel(int Caller)
Checked during operation, returns true if so and PerformancePanel removed - not used from v2....
Definition: InterfaceUnit.cpp:19258
TInterface::BuildOneRailwayCouplingMap
short BuildOneRailwayCouplingMap(unsigned char PlayerNumber)
store coupling map for a given railway name, return number of bytes needed for datagram
Definition: InterfaceUnit.cpp:24169
TimeTimeLoc
@ TimeTimeLoc
Definition: TrainUnit.h:66
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1507
TTrain::TimeToExit
float TimeToExit
in minutes: new for multiplayer, -1 = > 60 mins
Definition: TrainUnit.h:450
TInterface::TimetableChangedInAZOrderFlag
bool TimetableChangedInAZOrderFlag
used to give a warning message that changes will be discarded if proceed
Definition: InterfaceUnit.h:1307
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6989
TInterface::AddTrackButtonClick
void __fastcall AddTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:846
TInterface::SpeedButton92
TSpeedButton * SpeedButton92
Definition: InterfaceUnit.h:634
TInterface::DeleteMenuItemClick
void __fastcall DeleteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10818
TTrain::Derailed
bool Derailed
Definition: TrainUnit.h:482
TInterface::ConflictAnalysisButton
TButton * ConflictAnalysisButton
Definition: InterfaceUnit.h:268
TInterface::MMoveTextGraphicUserGraphicFoundFlag
bool MMoveTextGraphicUserGraphicFoundFlag
Mouse move flags to prevent repeated event logs.
Definition: InterfaceUnit.h:1251
TTextHandler::TextVectorPush
void TextVectorPush(int Caller, TTextItem Text)
push &Text onto TextVector & reset the size of the railway if necessary
Definition: TextUnit.cpp:505
TInterface::TTClockAdjButton
TBitBtn * TTClockAdjButton
Definition: InterfaceUnit.h:239
TInterface::PowerEditBoxKeyUp
void __fastcall PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:14086
TInterface::MPCPHostIPEditBoxKeyUp
void __fastcall MPCPHostIPEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:24695
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17639
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:655
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7364
TTrainController::SaveSessionLockedRoutes
void SaveSessionLockedRoutes(int Caller, std::ofstream &SessionFile)
save locked routes to a session file
Definition: TrainUnit.cpp:15620
API::add_metadata_str
void add_metadata_str(const AnsiString &label, AnsiString *data)
add pointer to string variable to monitor value
Definition: API.cpp:22
TInterface::OpenHelpMenuItemClick
void __fastcall OpenHelpMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13854
TTrain::OriginalPowerAtRail
double OriginalPowerAtRail
new at v2.4.0 to store value before a failure so it can be restored from here when repaired
Definition: TrainUnit.h:444
TInterface::CheckPerformanceFile
bool CheckPerformanceFile(int Caller, std::ifstream &InFile)
Check the performance file embedded within a session file & return false for error,...
Definition: InterfaceUnit.cpp:21607
TInterface::TInterface
__fastcall TInterface(TComponent *Owner)
constructor
Definition: InterfaceUnit.cpp:84
TInterface::SpeedButton15
TSpeedButton * SpeedButton15
Definition: InterfaceUnit.h:557
clB4G5R5
#define clB4G5R5
Definition: GraphicUnit.h:244
TTrain::NewTrainService
void NewTrainService(int Caller, bool NoLogFlag)
Carry out the actions needed when a train forms a new service (code Fns)
Definition: TrainUnit.cpp:6457
TInterface::TooLongMessageSentFlag
bool TooLongMessageSentFlag
indicates that the length of a location element might be too long (>200m), so it won't be given again
Definition: InterfaceUnit.h:1297
Timetable
@ Timetable
Definition: TrainUnit.h:60
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TInterface
Definition: InterfaceUnit.h:91
TTextHandler::SetFontStyleFromInt
TFontStyles SetFontStyleFromInt(int Caller, int Input)
used in loading from a file
Definition: TextUnit.cpp:126
TInterface::RemoveTrainMenuItemClick
void __fastcall RemoveTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12928
TInterface::RotRightMenuItemClick
void __fastcall RotRightMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10227
TTrain::AbleToMoveButForSignal
bool AbleToMoveButForSignal(int Caller)
Indicates that a train is only prevented from moving by a signal - used to allow appropriate popup me...
Definition: TrainUnit.cpp:7029
TTrainController::OpActionPanelVisible
bool OpActionPanelVisible
new v2.2.0 flag to prevent time to act functions when not visible
Definition: TrainUnit.h:799
TInterface::SaveInterface
void SaveInterface(int Caller, std::ofstream &SessionFile)
Save interface part of a session file.
Definition: InterfaceUnit.cpp:20153
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:614
TInterface::AcceptDragging
void __fastcall AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
Definition: InterfaceUnit.cpp:5781
TInterface::AllRailwaysCouplingPair
TCouplingPair AllRailwaysCouplingPair
Definition: InterfaceUnit.h:1104
Parapet
@ Parapet
Definition: TrackUnit.h:66
TTrack::GapFlashRedPosition
int GapFlashRedPosition
TrackVectorPosition of the gap element that is flashing green or red.
Definition: TrackUnit.h:764
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17666
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:72
TInterface::RouteFlashDuration
float RouteFlashDuration
duration of the route flash period
Definition: InterfaceUnit.h:1349
TInterface::SpeedButton4
TSpeedButton * SpeedButton4
Definition: InterfaceUnit.h:546
TTrainController::SignalStopWarning
bool SignalStopWarning
Definition: TrainUnit.h:791
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:269
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9104
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17612
TDisplay::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: DisplayUnit.cpp:521
TTrain::SignallerStopBrakeRate
double SignallerStopBrakeRate
the train brake rate when stopping under signaller control
Definition: TrainUnit.h:434
TInterface::SkipTimetabledActionsMenuItemClick
void __fastcall SkipTimetabledActionsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12149
TTrainController::SignallerTrainRemovedOnAutoSigsRoute
bool SignallerTrainRemovedOnAutoSigsRoute
true if train was on an AutoSigsRoute when removed by the signaller
Definition: TrainUnit.h:797
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:801
TTrainController::MRSLow
bool MRSLow
Definition: TrainUnit.h:805
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:776
TInterface::MPHostClient
TIdUDPClient * MPHostClient
Definition: InterfaceUnit.h:741
TTrain::Crashed
bool Crashed
Definition: TrainUnit.h:482
TInterface::SpeedButton44
TSpeedButton * SpeedButton44
Definition: InterfaceUnit.h:586
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:146
TInterface::ScreenRightButton
TBitBtn * ScreenRightButton
Definition: InterfaceUnit.h:284
TTrain::HeadCodePosition
Graphics::TBitmap * HeadCodePosition[4]
Set from the HeadCodeGrPtr[4] pointer values, HeadCodePosition[0] is always the front,...
Definition: TrainUnit.h:496
TInterface::OAListBox
TListBox * OAListBox
Operator action list, sits inside OperatorActionPanel and lists trains in ascending order of time to ...
Definition: InterfaceUnit.h:443
TTrain::TrainID
int TrainID
the train's identification number
Definition: TrainUnit.h:368
TInterface::SaveTTButton
TButton * SaveTTButton
Definition: InterfaceUnit.h:180
TUtilities::CheckStringDouble
bool CheckStringDouble(AnsiString &DoubleString)
checks the string represents a valid double value, returns true for success. Added at v2....
Definition: Utilities.cpp:370
TInterface::SpeedButton63
TSpeedButton * SpeedButton63
Definition: InterfaceUnit.h:605
TRailGraphics::bmLightBlueRect
Graphics::TBitmap * bmLightBlueRect
Definition: GraphicUnit.h:523
TInterface::MPHPLoadCouplingFileButtonClick
void __fastcall MPHPLoadCouplingFileButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:23557
TInterface::NonSigRouteStartMarker
TGraphicElement * NonSigRouteStartMarker
Definition: InterfaceUnit.h:1430
clB3G3R3
#define clB3G3R3
Definition: GraphicUnit.h:186
TInterface::SpeedButton53
TSpeedButton * SpeedButton53
Definition: InterfaceUnit.h:595
TInterface::SpeedButton107
TSpeedButton * SpeedButton107
Definition: InterfaceUnit.h:649
TTrainController::TrainVectorAt
TTrain & TrainVectorAt(int Caller, int VecPos)
Return a reference to the train at position VecPos in the TrainVector, carries out range checking on ...
Definition: TrainUnit.cpp:15896
TInterface::EditMenuClick
void __fastcall EditMenuClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9699
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:136
Nil
@ Nil
Definition: Utilities.h:37
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12324
TInterface::ModeMenu
TMenuItem * ModeMenu
Definition: InterfaceUnit.h:456
TInterface::SpeedButton112
TSpeedButton * SpeedButton112
Definition: InterfaceUnit.h:654
TInterface::MTBFEditBoxClick
void __fastcall MTBFEditBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14927
TInterface::TEVPtr
TTEVPtr TEVPtr
Definition: InterfaceUnit.h:1454
TInterface::MasterClock
TTimer * MasterClock
the program clock (not the timetable clock)
Definition: InterfaceUnit.h:537
TInterface::OutputLog6MouseDown
void __fastcall OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13783
TRailGraphics::SpeedBut70GrndBlackGlyph
Graphics::TBitmap * SpeedBut70GrndBlackGlyph
Definition: GraphicUnit.h:1070
TTrainController::NumFailures
int NumFailures
Definition: TrainUnit.h:848
TInterface::CreateEditTTTitle
AnsiString CreateEditTTTitle
the title of the timetable currently being edited - i.e. the filename without the '....
Definition: InterfaceUnit.h:1190
TInterface::AboutMenuItemClick
void __fastcall AboutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13833
TTrainController::TOpTimeToActMultiMapIterator
TOpTimeToActMultiMap::iterator TOpTimeToActMultiMapIterator
Definition: TrainUnit.h:783
TInterface::SpeedButton6
TSpeedButton * SpeedButton6
Definition: InterfaceUnit.h:548
TTrack
Definition: TrackUnit.h:544
TRailGraphics::CouplingExit6
Graphics::TBitmap * CouplingExit6
Definition: GraphicUnit.h:556
TInterface::OperatorActionPanelStartDrag
void __fastcall OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5874
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:848
TInterface::PlayerFiveSecondTimer
int PlayerFiveSecondTimer
Definition: InterfaceUnit.h:1132
TInterface::OperateRailwayMenuItem
TMenuItem * OperateRailwayMenuItem
Definition: InterfaceUnit.h:461
TInterface::SaveRailwayTBPButton
TBitBtn * SaveRailwayTBPButton
Save button on TrackBuildPanel.
Definition: InterfaceUnit.h:108
TTrain::ExitSpeedFull
double ExitSpeedFull
speed when leaving the next element
Definition: TrainUnit.h:422
TInterface::MTBFLabel
TLabel * MTBFLabel
Definition: InterfaceUnit.h:520
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1368
TInterface::SelectBitmap
Graphics::TBitmap * SelectBitmap
the graphic defined by Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1354
TInterface::PreventGapOffsetResetting
bool PreventGapOffsetResetting
during gap setting gaps are highlighted in turn for the user to select the matching gap,...
Definition: InterfaceUnit.h:1265
TInterface::TakeSignallerControlMenuItem
TMenuItem * TakeSignallerControlMenuItem
Definition: InterfaceUnit.h:498
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TInterface::Pasting
@ Pasting
Definition: InterfaceUnit.h:1019
TInterface::AddTextButton
TBitBtn * AddTextButton
Definition: InterfaceUnit.h:101
TInterface::LoadRailwayMenuItem
TMenuItem * LoadRailwayMenuItem
Definition: InterfaceUnit.h:447
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TInterface::CrashImage
TImage * CrashImage
Definition: InterfaceUnit.h:300
TTrainController::RandomFailureCounter
unsigned int RandomFailureCounter
new at v2.4.0 for train failures, resets after 53 seconds (53 prime so can trigger at any clock time)
Definition: TrainUnit.h:864
TInterface::SpeedButton123
TSpeedButton * SpeedButton123
Definition: InterfaceUnit.h:665
TInterface::USERGRAPHICS_DIR_NAME
static const UnicodeString USERGRAPHICS_DIR_NAME
Definition: InterfaceUnit.h:1003
TInterface::mbLeftDown
bool mbLeftDown
true when the left mouse button is down
Definition: InterfaceUnit.h:1245
TInterface::SpeedButton115
TSpeedButton * SpeedButton115
Definition: InterfaceUnit.h:657
TTrain::RepeatShuttleOrNewNonRepeatService
void RepeatShuttleOrNewNonRepeatService(int Caller, bool NoLogFlag)
Carry out the actions needed to create either a new shuttle service or (if all repeats have finished)...
Definition: TrainUnit.cpp:6871
TTrainController::TwoLocationList
TServiceCallingLocsList TwoLocationList
Definition: TrainUnit.h:858
TInterface::ProgramVersion
UnicodeString ProgramVersion
Definition: InterfaceUnit.h:989
TInterface::TTClockResetButton
TButton * TTClockResetButton
Definition: InterfaceUnit.h:254
TUtilities::CheckAndReadFileInt
bool CheckAndReadFileInt(std::ifstream &InFile, int Lowest, int Highest, int &OutInt)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success ...
Definition: Utilities.cpp:280
TInterface::TempCursor
TCursor TempCursor
stores the screen cursor while a temporary cursor (ususlly an hourglass) is displayed
Definition: InterfaceUnit.h:1419
Interface
TInterface * Interface
Definition: InterfaceUnit.cpp:69
TInterface::SpeedButton61
TSpeedButton * SpeedButton61
Definition: InterfaceUnit.h:603
TInterface::ExitSimulationMenuItem
TMenuItem * ExitSimulationMenuItem
Definition: InterfaceUnit.h:708
TDisplay::HideWarningLog
void HideWarningLog(int Caller)
Hide all the warnings from the top part of the screen - for timetable clock adjustment.
Definition: DisplayUnit.cpp:550
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:127
TUtilities::DecimalPoint
char DecimalPoint
added at v2.4.0 so can use the local value in loaded session files
Definition: Utilities.h:50
TInterface::BuildDynamicMapFromHostDatagram
bool BuildDynamicMapFromHostDatagram(int Caller, int TTTime, TDynamicMap &DMap, TBytes Buffer)
converse of BuildDatagramFromHostMap
Definition: InterfaceUnit.cpp:25053
TInterface::AllRailwaysCouplingMap
TCouplingMap AllRailwaysCouplingMap
Definition: InterfaceUnit.h:1105
TInterface::ConstructPrefDir
TOnePrefDir * ConstructPrefDir
the Pref Dir under construction
Definition: InterfaceUnit.h:1439
TInterface::SpeedButton81
TSpeedButton * SpeedButton81
Definition: InterfaceUnit.h:623
TInterface::SigsOnLeftImage1
TImage * SigsOnLeftImage1
Definition: InterfaceUnit.h:317
TInterface::BuildTrackMenuItemClick
void __fastcall BuildTrackMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:829
TUtilities::DelayMode
TDelayMode DelayMode
Definition: Utilities.h:74
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2976
TInterface::ClearandRebuildRailway
void ClearandRebuildRailway(int Caller)
Clear screen and rebuild it from stored data, uses HiddenScreen to avoid flicker.
Definition: InterfaceUnit.cpp:15479
TInterface::DisplayOneTTLineInPanel
void DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
Display a line from the TimetableEditVector (consists of a series of AnsiStrings, each of which repre...
Definition: InterfaceUnit.cpp:5545
TInterface::PlanPrefDirsMenuItem
TMenuItem * PlanPrefDirsMenuItem
Definition: InterfaceUnit.h:458
TInterface::AreAnyTimesInCurrentEntry
bool AreAnyTimesInCurrentEntry()
Search the timetable entry pointed to by TTCurrentEntryPtr and if any times (HH:MM) are present retur...
Definition: InterfaceUnit.cpp:5637
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9228
TInterface::AutoRouteStartMarker
TGraphicElement * AutoRouteStartMarker
Definition: InterfaceUnit.h:1430
TInterface::RestoreTTButtonClick
void __fastcall RestoreTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4576
TInterface::SaveTTButtonClick
void __fastcall SaveTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4189
TInterface::FormCreate
void __fastcall FormCreate(TObject *Sender)
Definition: InterfaceUnit.cpp:716
TGraphicElement::SetSourceRect
void SetSourceRect(int Left, int Top)
Set SourceRect member values from those supplied and existing Width & Height - ensure this is only ca...
Definition: TrackUnit.h:454
TTrack::SelectPush
void SelectPush(TTrackElement TrackElement)
Store a TrackElement in the SelectVector.
Definition: TrackUnit.h:919
TTrain::ExitPair
THVShortPair ExitPair
H & V coordinates of the exit element related to TimeToExit, new for multiplayer.
Definition: TrainUnit.h:468
TAllRoutes::SignallerRemovedTrainAutoRoute
TOneRoute SignallerRemovedTrainAutoRoute
if train was on an AutoSigsRoute when removed then this stores the route so that signals can be reset
Definition: TrackUnit.h:1694
TInterface::SpeedButton7
TSpeedButton * SpeedButton7
Definition: InterfaceUnit.h:549
TTrainController::MassHigh
bool MassHigh
Definition: TrainUnit.h:805
TInterface::TimetablePanel
TPanel * TimetablePanel
'Create a timetable'/'Edit a timetable' panel that contains the topmost buttons (show/hide & exit)
Definition: InterfaceUnit.h:398
TInterface::OneRailwayCouplingMap
TCouplingMap OneRailwayCouplingMap
Definition: InterfaceUnit.h:1105
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2111
TTrain::PlotTrainWithNewBackgroundColour
void PlotTrainWithNewBackgroundColour(int Caller, TColor NewBackgroundColour, TDisplay *Disp)
Changes the train's background colour (e.g. to pale green if stopped at a station) Note that this use...
Definition: TrainUnit.cpp:3580
TInterface::LoadSessionMenuItem
TMenuItem * LoadSessionMenuItem
Definition: InterfaceUnit.h:451
TInterface::SpeedButton69
TSpeedButton * SpeedButton69
Definition: InterfaceUnit.h:611
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TInterface::OutputLog5MouseDown
void __fastcall OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13774
TInterface::ErrorButton
TBitBtn * ErrorButton
the 'Press to exit' button on the error screen
Definition: InterfaceUnit.h:292
TInterface::SpeedButton24
TSpeedButton * SpeedButton24
Definition: InterfaceUnit.h:566
TInterface::WarningFlash
bool WarningFlash
toggles on and off automatically at a cycle of about 0.5 sec, used to drive the warning icons during ...
Definition: InterfaceUnit.h:1313
TInterface::CurrentSpeedButton
TSpeedButton * CurrentSpeedButton
stores the selected track build element button during railway building
Definition: InterfaceUnit.h:1451
TInterface::MainScreenMouseDown
void __fastcall MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5895
TTrain::ExitTimeFull
TDateTime ExitTimeFull
times used in SetTrainMovementValues corresponding to the next element the train runs on
Definition: TrainUnit.h:462
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:157
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:784
TInterface::TotalTicks
unsigned int TotalTicks
total clock ticks
Definition: InterfaceUnit.h:1360
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2577
TInterface::SpeedTopLabel2
TLabel * SpeedTopLabel2
Definition: InterfaceUnit.h:146
TInterface::AnsiCouplingMap
TAnsiCouplingMap AnsiCouplingMap
Definition: InterfaceUnit.h:1043
TInterface::MMoveTextGraphicTextFoundFlag
bool MMoveTextGraphicTextFoundFlag
Definition: InterfaceUnit.h:1250
SignallerChangeDirection
@ SignallerChangeDirection
Definition: TrainUnit.h:54
TRailGraphics::GridBitmap
Graphics::TBitmap * GridBitmap
Definition: GraphicUnit.h:915
TInterface::PowerBottomLabel
TLabel * PowerBottomLabel
Definition: InterfaceUnit.h:224
TInterface::PasteMenuItem
TMenuItem * PasteMenuItem
Definition: InterfaceUnit.h:474
TInterface::TRlyUserInfo
Definition: InterfaceUnit.h:1055
TTextHandler::EnterAndDisplayNewText
void EnterAndDisplayNewText(int Caller, TTextItem Text, int HPos, int VPos)
add Text to TextVector and display it on the screen
Definition: TextUnit.cpp:190
TInterface::MPPlayerClient
TIdUDPClient * MPPlayerClient
Definition: InterfaceUnit.h:701
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12112
TInterface::CreateEditTTFileName
AnsiString CreateEditTTFileName
the full path and filename of the timetable file
Definition: InterfaceUnit.h:1188
TActionVectorEntry
Contains a single train action in a timetable - repeat entry is also of this class though no train ac...
Definition: TrainUnit.h:122
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12890
TTrainController::TotLateExitMins
float TotLateExitMins
Definition: TrainUnit.h:824
TInterface::ManualLCDownAttentionWarning
bool ManualLCDownAttentionWarning
Displays the manual LC down warning graphic in the panel on the LHS of the railway when there are no ...
Definition: InterfaceUnit.h:1514
TInterface::PerformanceLogButtonClick
void __fastcall PerformanceLogButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2302
TTrainController::CheckSessionContinuationAutoSigEntries
bool CheckSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for ContinuationAutoSigEntries, true for success.
Definition: TrainUnit.cpp:15742
TInterface::HideTTActionsListBox
void HideTTActionsListBox(int Caller)
makes TTActionsListBox invisible (if it was visible) and resterts the tt clock
Definition: InterfaceUnit.cpp:12461
IDInt
Definition: TrackUnit.h:493
TInterface::SelectLengthsMenuItemClick
void __fastcall SelectLengthsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10837
TInterface::NewSelectBitmapHLoc
int NewSelectBitmapHLoc
the new (during & at end of moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1366
TInterface::LoadUserGraphic
void LoadUserGraphic(int Caller)
Load a user-defined graphic (bmp, gif, jpg, png).
Definition: InterfaceUnit.cpp:22936
TInterface::TTCurrentEntryPtr
TTEVPtr TTCurrentEntryPtr
Definition: InterfaceUnit.h:1454
TRunningEntry
TRunningEntry
contains status info for each train
Definition: TrainUnit.h:87
TInterface::OutputLog6
TLabel * OutputLog6
Definition: InterfaceUnit.h:334
TUtilities
Definition: Utilities.h:41
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4428
TInterface::CreateTimetableMenuItemClick
void __fastcall CreateTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3206
TInterface::ExportTTButtonClick
void __fastcall ExportTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4658
TDisplay
Definition: DisplayUnit.h:48
TInterface::SpeedButton9
TSpeedButton * SpeedButton9
Definition: InterfaceUnit.h:551
TInterface::TTClockxEighthButtonClick
void __fastcall TTClockxEighthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14515
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10210
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:144
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:866
TInterface::Text_X
int Text_X
the 'X' pixel value for an item of text
Definition: InterfaceUnit.h:1403
TInterface::SpeedVariableLabel
TLabel * SpeedVariableLabel
Definition: InterfaceUnit.h:217
TInterface::SpeedButton49
TSpeedButton * SpeedButton49
Definition: InterfaceUnit.h:591
TInterface::SigPrefNonConsecButton
TBitBtn * SigPrefNonConsecButton
Definition: InterfaceUnit.h:692
TTrain::StoppedWithoutPower
bool StoppedWithoutPower
Definition: TrainUnit.h:483
TInterface::GetTrainStatusFloat
AnsiString GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
used for floating window to display train status
Definition: InterfaceUnit.cpp:18246
TInterface::PowerVariableLabel
TLabel * PowerVariableLabel
Definition: InterfaceUnit.h:225
TActionEventType
TActionEventType
Used for reporting error conditions & warnings.
Definition: TrainUnit.h:39
TInterface::GapsNotSetImage
TImage * GapsNotSetImage
Definition: InterfaceUnit.h:314
TInterface::Level1Mode
enum TInterface::TLevel1Mode Level1Mode
TInterface::CallLogTickerLabel
TLabel * CallLogTickerLabel
diagnostic label displaying the call log depth, made visible by ctrl+ alt+ 2
Definition: InterfaceUnit.h:356
TInterface::TimetableEditVector
TTimetableEditVector TimetableEditVector
Definition: InterfaceUnit.h:1457
TTrainController::TrainExistsAtIdent
bool TrainExistsAtIdent(int Caller, int TrainID)
new at v2.4.0 return true if find the train (added at v2.4.0 as can select a removed train in OAListB...
Definition: TrainUnit.cpp:9979
SignallerJoin
@ SignallerJoin
Definition: TrainUnit.h:53
TTrain::StepForwardFlag
bool StepForwardFlag
set when the signaller command to step forward one element has been given
Definition: TrainUnit.h:404
TInterface::SaveRailwayDialog
TSaveDialog * SaveRailwayDialog
Definition: InterfaceUnit.h:532
TInterface::TTClockAdjustWarningPanel
TPanel * TTClockAdjustWarningPanel
Definition: InterfaceUnit.h:248
TInterface::TServiceInfo::TServiceInfo
TServiceInfo()
Definition: InterfaceUnit.cpp:25243
TTrainController::TotEarlyExitMins
float TotEarlyExitMins
Definition: TrainUnit.h:820
TInterface::TrainTTInfoOnOffMenuItemClick
void __fastcall TrainTTInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5756
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:96
TTrainController::Operate
void Operate(int Caller)
called every clock tick to introduce new trains and update existing trains
Definition: TrainUnit.cpp:9242
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:152
TTrainController::SkippedTTEvents
int SkippedTTEvents
Definition: TrainUnit.h:843
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:901
TTrain::PowerAtRail
double PowerAtRail
< the running total of all random delays including knock-on delays for a single train,...
Definition: TrainUnit.h:442
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:762
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14324
TAllRoutes::LevelCrossingBarrierDownDelay
const float LevelCrossingBarrierDownDelay
the full value in seconds for which the level crossing flashes prior to opening to trains
Definition: TrackUnit.h:1682
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1675
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TInterface::SetSaveMenuAndButtons
void SetSaveMenuAndButtons(int Caller)
Called during the ClockTimer2 function to set screen boundaries, buttons & menu items.
Definition: InterfaceUnit.cpp:18824
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TInterface::TIMETABLE_DIR_NAME
static const UnicodeString TIMETABLE_DIR_NAME
Definition: InterfaceUnit.h:998
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:129
TInterface::SaveImageAndPrefDirsMenuItem
TMenuItem * SaveImageAndPrefDirsMenuItem
Definition: InterfaceUnit.h:491
TInterface::LoadRailwayMenuItemClick
void __fastcall LoadRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2388
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7701
TInterface::FormKeyUp
void __fastcall FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13722
TInterface::SkipListExitImage
TImage * SkipListExitImage
Definition: InterfaceUnit.h:749
TInterface::CopyTTEntryKeyFlag
bool CopyTTEntryKeyFlag
Definition: InterfaceUnit.h:1328
TTrainDataEntry::TrainOperatingDataVector
TTrainOperatingDataVector TrainOperatingDataVector
operating information for the train including all its repeats
Definition: TrainUnit.h:227
TTrain::DelayedRandMins
double DelayedRandMins
Definition: TrainUnit.h:436
TInterface::OutputLog9MouseDown
void __fastcall OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13813
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:628
TInterface::RecoverClipboardMessageSent
bool RecoverClipboardMessageSent
indicates that the warning about pasting at top left in a new application has been given,...
Definition: InterfaceUnit.h:1267
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:146
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:883
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1493
TInterface::SpeedButton80
TSpeedButton * SpeedButton80
Definition: InterfaceUnit.h:622
TTrain::IsThereAnAdjacentTrain
bool IsThereAnAdjacentTrain(int Caller, TTrain *&TrainToBeJoinedBy)
Definition: TrainUnit.cpp:5199
TInterface::ApproachLocking
void ApproachLocking(int Caller, TDateTime Now)
Function that deals with approach locking during ClockTimer2 function.
Definition: InterfaceUnit.cpp:17592
TInterface::TimetableTitle
AnsiString TimetableTitle
the titles of the loaded railway and loaded timetable, i.e. the filenames without the extension
Definition: InterfaceUnit.h:1202
TInterface::BlackBgndMenuItemClick
void __fastcall BlackBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13877
TInterface::SpeedButton114
TSpeedButton * SpeedButton114
Definition: InterfaceUnit.h:656
TInterface::Deleting
@ Deleting
Definition: InterfaceUnit.h:1019
TInterface::RestoreAllDefaultLengthsButton
TBitBtn * RestoreAllDefaultLengthsButton
Definition: InterfaceUnit.h:112
TInterface::ClearAllMenuItemClick
void __fastcall ClearAllMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3132
TUtilities::EventLog
std::deque< AnsiString > EventLog
event store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:65
TPrefDirElement::SetXLink
void SetXLink(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:346
TInterface::MoveTTEntryUpKeyFlag
bool MoveTTEntryUpKeyFlag
Definition: InterfaceUnit.h:1326
TActionVectorEntry::FormatType
TTimetableFormatType FormatType
defines the timetable action type
Definition: TrainUnit.h:140
TInterface::TextBox
TEdit * TextBox
the edit box that accepts text to be added
Definition: InterfaceUnit.h:123
TGraphicElement::GetHPos
int GetHPos()
Definition: TrackUnit.h:443
TInterface::SpeedButton133
TSpeedButton * SpeedButton133
Definition: InterfaceUnit.h:675
TOnePrefDir::SearchVectorSize
unsigned int SearchVectorSize() const
Return the vector size.
Definition: TrackUnit.h:1380
TDisplay::PerformanceMemo
TMemo *& PerformanceMemo
Definition: DisplayUnit.h:68
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:706
Moderate
@ Moderate
Definition: Utilities.h:37
TTrainController::TimetableStartTime
TDateTime TimetableStartTime
the start time of the current timetable
Definition: TrainUnit.h:704
TTrainController::UnplotTrains
void UnplotTrains(int Caller)
unplot all trains from screen
Definition: TrainUnit.cpp:9629
TInterface::SpeedButton18
TSpeedButton * SpeedButton18
Definition: InterfaceUnit.h:560
TInterface::ScreenGridFlag
bool ScreenGridFlag
true when the screen grid is displayed
Definition: InterfaceUnit.h:1275
TInterface::InfoCaptionStore
AnsiString InfoCaptionStore
temporary store for the information panel caption
Definition: InterfaceUnit.h:1196
TRailGraphics::smBrightGreen
Graphics::TBitmap * smBrightGreen
Definition: GraphicUnit.h:892
TInterface::CopiedEntryFlag
bool CopiedEntryFlag
true when CopiedEntryStr holds a timetable entry in the timetable editor
Definition: InterfaceUnit.h:1223
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15511
TInterface::SpeedButton89
TSpeedButton * SpeedButton89
Definition: InterfaceUnit.h:631
TTrainController::EarlyArrivals
int EarlyArrivals
Definition: TrainUnit.h:829
TInterface::BuildDatagramFromHostMap
void BuildDatagramFromHostMap(int Caller, TBytes &buffer, TDynamicMap DynamicMap)
converts a host's dynamic map into a datagram; TTTime is a 4 byte timetable time in secs (allows up t...
Definition: InterfaceUnit.cpp:25001
TPrefDirElement::SetEXNumber
void SetEXNumber(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:358
TInterface::AnyTTKeyFlagSet
bool AnyTTKeyFlagSet()
Definition: InterfaceUnit.h:1467
TTrainController::CreateFormattedTimetable
void CreateFormattedTimetable(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir)
Examines the internal timetable (TrainDataVector) and creates from it a chronological (....
Definition: TrainUnit.cpp:15909
TInterface::SetTopIndex
void SetTopIndex(int Caller)
This used in timetable functions when shift keys pressed to make sure that the highlighted entry rema...
Definition: InterfaceUnit.cpp:15452
TTrack::RouteFlashFlag
bool RouteFlashFlag
true while a route is flashing prior to being set
Definition: TrackUnit.h:748
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13626
TInterface::PowerToggleButtonClick
void __fastcall PowerToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14065
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1285
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13401
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:150
Major
@ Major
Definition: Utilities.h:37
TInterface::SpeedButton46
TSpeedButton * SpeedButton46
Definition: InterfaceUnit.h:588
Points
@ Points
Definition: TrackUnit.h:65
TInterface::PlayerMakingInitialContactFlag
bool PlayerMakingInitialContactFlag
Definition: InterfaceUnit.h:1143
TTrainController::TotLatePassMins
float TotLatePassMins
Definition: TrainUnit.h:823
TTrainController::StripSpaces
void StripSpaces(int Caller, AnsiString &Input)
Strip both leading and trailing spaces at ends of Input and spaces before and after all commas and se...
Definition: TrainUnit.cpp:14219
TInterface::Delay
void Delay(int Caller, double Msec)
Delays operation for the set time in milliseconds.
Definition: InterfaceUnit.cpp:15874
TTrain::JoinedOtherTrainFlag
bool JoinedOtherTrainFlag
true when the train has joined another train following an 'Fjo' timetable command or a signaller join...
Definition: TrainUnit.h:390
TTrainController::OpActionPanelHintDelayCounter
unsigned int OpActionPanelHintDelayCounter
new v2.2.0 on start operation delays the op action panel headcode display for about 3 secs while hint...
Definition: TrainUnit.h:862
TTrainController::BFLow
bool BFLow
Definition: TrainUnit.h:805
TInterface::OutputLog7
TLabel * OutputLog7
Definition: InterfaceUnit.h:335
TTrainController::TotArrDepPass
int TotArrDepPass
Definition: TrainUnit.h:846
TInterface::LastNonCtrlOrShiftKeyDown
int LastNonCtrlOrShiftKeyDown
value of last key (other than Ctrl or Shift) pressed down - to prevent repeated FormKeyDown calls fro...
Definition: InterfaceUnit.h:1364
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4163
SignallerPassRedSignal
@ SignallerPassRedSignal
Definition: TrainUnit.h:54
TRailGraphics::ChangeForegroundColour
void ChangeForegroundColour(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
Definition: GraphicUnit.cpp:3423
TInterface::TextItem
int TextItem
used to store a single item of text
Definition: InterfaceUnit.h:1409
TInterface::UserGraphicButtonClick
void __fastcall UserGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14949
TInterface::OriginalTimetableEditVector
TTimetableEditVector OriginalTimetableEditVector
the complete timetable as a list of AnsiStrings for use in edit timetable functions
Definition: InterfaceUnit.h:1457
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1850
TInterface::MPCPHostImage
TImage * MPCPHostImage
Definition: InterfaceUnit.h:719
TInterface::PresetAutoSigRoutesButtonClick
void __fastcall PresetAutoSigRoutesButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14671
TInterface::SigPrefNonConsecButtonClick
void __fastcall SigPrefNonConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2195
TRailGraphics::SpeedBut68GrndBlackGlyph
Graphics::TBitmap * SpeedBut68GrndBlackGlyph
Definition: GraphicUnit.h:1068
TTrain::SignallerRemoved
bool SignallerRemoved
set when removed under signaller control to force a removal from the display at the next clock tick
Definition: TrainUnit.h:398
TTrain::FrontCodePtr
Graphics::TBitmap * FrontCodePtr
points to the front headcode segment, this is set to red or blue depending on TrainMode
Definition: TrainUnit.h:500
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16927
TInterface::MMovePrefDirSelFlag
bool MMovePrefDirSelFlag
Definition: InterfaceUnit.h:1248
TInterface::TwoLocationNamePanel
TPanel * TwoLocationNamePanel
Definition: InterfaceUnit.h:693
TInterface::InvalidIPAddress
bool InvalidIPAddress(AnsiString Text)
< Utility used in PopulateCouplingMap for ID conversion
Definition: InterfaceUnit.cpp:25181
Continuation
@ Continuation
Definition: TrackUnit.h:65
TInterface::ScreenUpButton
TBitBtn * ScreenUpButton
Definition: InterfaceUnit.h:286
TInterface::TTServiceSyntaxCheckButton
TButton * TTServiceSyntaxCheckButton
Definition: InterfaceUnit.h:178
TTrainController::CallOnWarning
bool CallOnWarning
Definition: TrainUnit.h:791
TInterface::SetLengthsButton
TBitBtn * SetLengthsButton
Definition: InterfaceUnit.h:106
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrain::ActualArrivalTime
TDateTime ActualArrivalTime
location departure time and 'train ready to start' time (TRSTime is 10 seconds before the ReleaseTime...
Definition: TrainUnit.h:464
GraphicUnit.h
TInterface::AppActivate
void __fastcall AppActivate(TObject *Sender)
Definition: InterfaceUnit.cpp:777
TInterface::MPHPCancelButtonClick
void __fastcall MPHPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:23659
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3739
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6018
TInterface::AddTextButtonClick
void __fastcall AddTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1056
TInterface::MMoveTrackSelFlag
bool MMoveTrackSelFlag
Definition: InterfaceUnit.h:1247
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TInterface::ReselectMenuItemClick
void __fastcall ReselectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9747
TInterface::SpeedButton94
TSpeedButton * SpeedButton94
Definition: InterfaceUnit.h:636
TInterface::SaveTTAsKeyFlag
bool SaveTTAsKeyFlag
Definition: InterfaceUnit.h:1337
TInterface::SaveTTEntryButtonClick
void __fastcall SaveTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4039
TInterface::TimetablePanelLabel
TLabel * TimetablePanelLabel
label to the left of TimetablePanel
Definition: InterfaceUnit.h:350
TTrack::PointFlashFlag
bool PointFlashFlag
true when points are flashing during manual change
Definition: TrackUnit.h:746
TTrainController::OnTimeDeps
int OnTimeDeps
Definition: TrainUnit.h:839
TRailGraphics::CouplingExit9
Graphics::TBitmap * CouplingExit9
Definition: GraphicUnit.h:559
TTrain::RestoreTimetableLocation
AnsiString RestoreTimetableLocation
stores the location name at which signaller control is taken, to ensure that it is back at that locat...
Definition: TrainUnit.h:474
TInterface::SpeedButton40
TSpeedButton * SpeedButton40
Definition: InterfaceUnit.h:582
TTrainController::TimetableIntegrityCheck
bool TimetableIntegrityCheck(int Caller, char *FileName, bool GiveMessages, bool CheckLocationsExistInRailway)
Checks overall timetable integrity, calls many other specific checking functions, returns true for su...
Definition: TrainUnit.cpp:10368
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TDisplay::Left
int Left()
Return the left pixel position of the screen.
Definition: DisplayUnit.h:115
TTrain::SignallerMaxSpeed
int SignallerMaxSpeed
maximum train speed under signaller control (in km/h)
Definition: TrainUnit.h:362
TInterface::BufferAttentionImage
TImage * BufferAttentionImage
Definition: InterfaceUnit.h:297
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12155
TTrainController::SendPerformanceSummary
void SendPerformanceSummary(int Caller, std::ofstream &PerfFile)
At the end of operation a summary of overall performance is sent to the performance file by this func...
Definition: TrainUnit.cpp:19364
TInterface::OperatorActionButtonClick
void __fastcall OperatorActionButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14779
TInterface::SpeedEditBox
TEdit * SpeedEditBox
Definition: InterfaceUnit.h:214
TInterface::InfoVector
TInfoVector InfoVector
Definition: InterfaceUnit.h:1067
TInterface::NumPlayers
int NumPlayers
Definition: InterfaceUnit.h:1131
TInterface::LoadRailwayDialog
TOpenDialog * LoadRailwayDialog
Definition: InterfaceUnit.h:526
TInterface::CopyMenuItem
TMenuItem * CopyMenuItem
Definition: InterfaceUnit.h:470
TInterface::ResetDefaultLengthButtonClick
void __fastcall ResetDefaultLengthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1613
RepairFailedTrain
@ RepairFailedTrain
Definition: TrainUnit.h:54
TInterface::NoOperMode
@ NoOperMode
Definition: InterfaceUnit.h:1008
TInterface::ErrorLogCalledFlag
bool ErrorLogCalledFlag
true when an error has been thrown, stops repeated calls to ErrorLog and stops the MasterClockTimer f...
Definition: InterfaceUnit.h:1233
TInterface::NextTTEntryKeyFlag
bool NextTTEntryKeyFlag
Definition: InterfaceUnit.h:1325
TInterface::RouteFlashStartTime
TDateTime RouteFlashStartTime
stores the starting time (timetable clock time) for route flashing
Definition: InterfaceUnit.h:1426
TInterface::PerformancePanelLabel
TLabel * PerformancePanelLabel
label at the top of PerformancePanel
Definition: InterfaceUnit.h:340
TInterface::BlueBgndMenuItemClick
void __fastcall BlueBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13929
TInterface::P5SCounter
int P5SCounter
Definition: InterfaceUnit.h:1134
TInterface::SetTrackLengths
void SetTrackLengths(int Caller, int Distance, int SpeedLimit)
Called during track building when setting distances, to calculate and set the individual track elemen...
Definition: InterfaceUnit.cpp:22143
TInterface::SpeedToggleButtonClick
void __fastcall SpeedToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13955
TTrainController::ContinuationEntryFloatingTTString
AnsiString ContinuationEntryFloatingTTString(int Caller, TTrainDataEntry *TTDEPtr, int RepeatNumber, int IncrementalMinutes, int IncrementalDigits)
Build string for use in floating window for expected trains at continuations.
Definition: TrainUnit.cpp:10010
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3356
TInterface::ModerateDelaysMenuItem
TMenuItem * ModerateDelaysMenuItem
Definition: InterfaceUnit.h:754
TGraphicElement::GetVPos
int GetVPos()
Definition: TrackUnit.h:448
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1510
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:87
TTrain::FollowOnServiceRef
AnsiString FollowOnServiceRef
Definition: TrainUnit.h:325
TTrain::SPADFlag
bool SPADFlag
set when running past a red signal without permission flags to indicate relevant stop conditions or p...
Definition: TrainUnit.h:480
TInterface::TTLabel5
TLabel * TTLabel5
Definition: InterfaceUnit.h:380
TInterface::HomeButtonClick
void __fastcall HomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9628
TInterface::PointFlashStartTime
TDateTime PointFlashStartTime
stores the starting time (timetable clock time) for points flashing
Definition: InterfaceUnit.h:1424
TInterface::TTLabel7
TLabel * TTLabel7
Definition: InterfaceUnit.h:382
TInterface::RailwayWebSiteMenuItemClick
void __fastcall RailwayWebSiteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13869
TInterface::BuildDatagramFromPlayerMap
void BuildDatagramFromPlayerMap(int Caller, char marker, AnsiString UserName, TBytes &buffer, TDynamicMap DynamicMap)
converts a player's dynamic map into a datagram; marker is a single digit to identify the datagram ty...
Definition: InterfaceUnit.cpp:24845
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:673
Minor
@ Minor
Definition: Utilities.h:37
TInterface::SpeedButton36
TSpeedButton * SpeedButton36
Definition: InterfaceUnit.h:578
TInterface::TTFirstServicePtr
TTEVPtr TTFirstServicePtr
Definition: InterfaceUnit.h:1454
TInterface::ClockTimer2
void ClockTimer2(int Caller)
The main loop, called every clock tick via MasterClockTimer.
Definition: InterfaceUnit.cpp:8451
TInterface::SpeedButton56
TSpeedButton * SpeedButton56
Definition: InterfaceUnit.h:598
TDisplay::PlotDashedRect
void PlotDashedRect(int Caller, TRect Rect)
Plot a dashed rectangle for the area defined by Rect, used when selecting display areas.
Definition: DisplayUnit.cpp:499
TInterface::NewTTEntryButtonClick
void __fastcall NewTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3603
TInterface::LoadSessionMenuItemClick
void __fastcall LoadSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3118
TInterface::SkipTTActionsListBox
TListBox * SkipTTActionsListBox
Definition: InterfaceUnit.h:745
TTrack::SelectVectorClear
void SelectVectorClear()
Definition: TrackUnit.h:924
TInterface::PerformanceFileName
AnsiString PerformanceFileName
full path and filename of the performance file
Definition: InterfaceUnit.h:1200
TInterface::AutoSigsButton
TBitBtn * AutoSigsButton
Definition: InterfaceUnit.h:230
TInterface::PopupMenu
TPopupMenu * PopupMenu
Definition: InterfaceUnit.h:523
TTrainController::OnTimeExits
int OnTimeExits
Definition: TrainUnit.h:841
TInterface::LoadSessionFlag
bool LoadSessionFlag
true when a session load command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:1243
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:263
TInterface::NoTrackMode
@ NoTrackMode
Definition: InterfaceUnit.h:1018
TInterface::TimetableValidFlag
bool TimetableValidFlag
indicates that a 'Validate timetable' button click in the timetable editor has succeeded
Definition: InterfaceUnit.h:1305
TInterface::ElapsedTimeTestFunctionStart
bool ElapsedTimeTestFunctionStart
Definition: InterfaceUnit.h:1178
TInterface::CancelSelectionFlag
bool CancelSelectionFlag
used in case pasting to avoid RecoverClipboard call when set
Definition: InterfaceUnit.h:1217
TInterface::TimetableControlMenuItem
TMenuItem * TimetableControlMenuItem
Definition: InterfaceUnit.h:499
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TUtilities::PerformanceFile
std::ofstream PerformanceFile
< the running total of all random delays including knock-on delays for all trains,...
Definition: Utilities.h:61
TInterface::ConvertToOtherHandSignalsMenuItemClick
void __fastcall ConvertToOtherHandSignalsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14809
TInterface::TTLabel15
TLabel * TTLabel15
Definition: InterfaceUnit.h:389
TInterface::PreferredRoute
bool PreferredRoute
true when AutoSig or preferred route building selected during operation (always same state as ConsecS...
Definition: InterfaceUnit.h:1261
TInterface::ConvertCRLFsToCommas
void ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
Used in timetable editing functions to convert any CRLFs in intended service entries to commas.
Definition: InterfaceUnit.cpp:5319
TInterface::OutputLog2MouseDown
void __fastcall OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13745
TInterface::MPHPGeneralLabel
TLabel * MPHPGeneralLabel
Definition: InterfaceUnit.h:727
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
TTrain::RevisedStoppedAtLoc
bool RevisedStoppedAtLoc() const
Definition: TrainUnit.h:513
TInterface::SpeedButton106
TSpeedButton * SpeedButton106
Definition: InterfaceUnit.h:648
TTrackElement::TempTrackMarker01
bool TempTrackMarker01
Definition: TrackUnit.h:138
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TInterface::LoadTimetableFromSessionFile
bool LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Loads timetable into memory from a session file, true if successful.
Definition: InterfaceUnit.cpp:20629
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:768
TInterface::SpeedButton125
TSpeedButton * SpeedButton125
Definition: InterfaceUnit.h:667
TInterface::SpeedButton21
TSpeedButton * SpeedButton21
Definition: InterfaceUnit.h:563
TUtilities::DateTimeStamp
AnsiString DateTimeStamp()
creates a string of the form 'dd/mm/yyyy hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:67
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:877
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4681
TInterface::SpeedButton64
TSpeedButton * SpeedButton64
Definition: InterfaceUnit.h:606
TInterface::AllEntriesTTListBoxMouseUp
void __fastcall AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4857
TInterface::TwoLocationNameCheckBox
TCheckBox * TwoLocationNameCheckBox
Definition: InterfaceUnit.h:696
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1702
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8634
TInterface::FontButton
TBitBtn * FontButton
Definition: InterfaceUnit.h:104
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:788
TInterface::NextTTEntryButtonClick
void __fastcall NextTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3521
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TInterface::~TInterface
__fastcall ~TInterface()
destructor
Definition: InterfaceUnit.cpp:678
TInterface::CancelTTEntryButtonClick
void __fastcall CancelTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4539
TInterface::TTEVPtr
std::vector< AnsiString >::iterator TTEVPtr
typedef for pointers to entries in edit timetable functions
Definition: InterfaceUnit.h:1164
TInterface::PlayerCancelJoinFlag
bool PlayerCancelJoinFlag
Definition: InterfaceUnit.h:1145
TInterface::SaveHeaderMenu1Click
void __fastcall SaveHeaderMenu1Click(TObject *Sender)
Definition: InterfaceUnit.cpp:3058
TInterface::TTStartTimePtr
TTEVPtr TTStartTimePtr
Definition: InterfaceUnit.h:1454
TInterface::TRlyUserInfo::TRlyUserInfo
TRlyUserInfo()
Definition: InterfaceUnit.cpp:25252
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:702
TInterface::TTClockAdjPanel
TPanel * TTClockAdjPanel
Definition: InterfaceUnit.h:247
TInterface::BuildTrainDataVectorForLoadFile
bool BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
Convert a stored timetable file (either as a stand alone file or within a session file) to a loaded t...
Definition: InterfaceUnit.cpp:20851
TInterface::ConflictPanel
TPanel * ConflictPanel
Definition: InterfaceUnit.h:271
TInterface::CompileAllEntriesMemoAndSetPointers
void CompileAllEntriesMemoAndSetPointers(int Caller)
Used during timetable editing funtions to compile the list of entries into the left hand long entry w...
Definition: InterfaceUnit.cpp:5067
TInterface::CopiedEntryStr
AnsiString CopiedEntryStr
a timetable entry that has been copied
Definition: InterfaceUnit.h:1186
TInterface::SpeedButton12
TSpeedButton * SpeedButton12
Definition: InterfaceUnit.h:554
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:19182
TInterface::SelectMenuItem
TMenuItem * SelectMenuItem
Definition: InterfaceUnit.h:467
TInterface::BuildDynamicMapFromPlayerDatagram
bool BuildDynamicMapFromPlayerDatagram(int Caller, TDynamicMap &DMap, TBytes Buffer, unsigned char &marker, AnsiString &UserName)
Converse of BuildDatagramFromPlayerMap.
Definition: InterfaceUnit.cpp:24909
TInterface::MoveTTEntryDownKeyFlag
bool MoveTTEntryDownKeyFlag
Definition: InterfaceUnit.h:1327
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1860
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4666
Connection
@ Connection
Definition: TrackUnit.h:75
TInterface::TTTextButtonClick
void __fastcall TTTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4697
TInterface::TDynamicMap
std::map< TNumHVPair, TServiceInfo, TDynamicMapComp > TDynamicMap
Definition: InterfaceUnit.h:1095
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3716
TTrainController::TrainFailedWarning
bool TrainFailedWarning
Flags to enable the relevant warning graphics to flash at the left hand side of the screen.
Definition: TrainUnit.h:791
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1677
TInterface::LengthOKButton
TBitBtn * LengthOKButton
distance/speed setting buttons - left to right & top to bottom
Definition: InterfaceUnit.h:115
TInterface::IsBecomeNewServiceAvailable
bool IsBecomeNewServiceAvailable(int Caller, int TrainID, AnsiString &NextServiceRef)
Check to see if a BecomeNewService popup otion is available - i.e stopped at location,...
Definition: InterfaceUnit.cpp:12607
TTrain::NextTrainID
static int NextTrainID
the ID value to be used for the next train that is created, static so that it doesn't need an object ...
Definition: TrainUnit.h:320
TInterface::PreviousTTEntryButtonClick
void __fastcall PreviousTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3562
TInterface::UserGraphicButton
TBitBtn * UserGraphicButton
Definition: InterfaceUnit.h:117
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16740
TInterface::Text_Y
int Text_Y
as above for 'Y'
Definition: InterfaceUnit.h:1405
TInterface::MPCPHostIPEditBox
TEdit * MPCPHostIPEditBox
Definition: InterfaceUnit.h:730
TInterface::MMoveCopyCutSelPickedUpFlag
bool MMoveCopyCutSelPickedUpFlag
Definition: InterfaceUnit.h:1249
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18454
TInterface::MultiplayerHostPanel
TPanel * MultiplayerHostPanel
Definition: InterfaceUnit.h:722
TInterface::DeleteTTEntryButton
TButton * DeleteTTEntryButton
Definition: InterfaceUnit.h:168
TInterface::ReselectUserGraphicClick
void __fastcall ReselectUserGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14982
TRailGraphics::SolidCircleRed
Graphics::TBitmap * SolidCircleRed
Definition: GraphicUnit.h:561
TInterface::TTClockAdd1mButtonClick
void __fastcall TTClockAdd1mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14594
TInterface::SubMinsButton
TButton * SubMinsButton
Definition: InterfaceUnit.h:177
TInterface::SpeedButton66
TSpeedButton * SpeedButton66
Definition: InterfaceUnit.h:608
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7062
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:561
TInterface::ValidateTimetableButtonClick
void __fastcall ValidateTimetableButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4356
TTrain::CumulativeDelayedRandMinsOneTrain
double CumulativeDelayedRandMinsOneTrain
< an additional random delay at a location
Definition: TrainUnit.h:440
TInterface::UserGraphicMoveVPos
int UserGraphicMoveVPos
used to store the original user graphic 'H' & 'V' positions for use during moving
Definition: InterfaceUnit.h:1415
TInterface::SpeedButton98
TSpeedButton * SpeedButton98
Definition: InterfaceUnit.h:640
TActionVectorEntry::LocationName
AnsiString LocationName
Definition: TrainUnit.h:124
TInterface::LoadTimetableMenuItem
TMenuItem * LoadTimetableMenuItem
Definition: InterfaceUnit.h:450
TInterface::SpeedButton95
TSpeedButton * SpeedButton95
Definition: InterfaceUnit.h:637
TPrefDirElement::SetTrackVectorPosition
void SetTrackVectorPosition(int TVPos)
Used in pasting pref dirs.
Definition: TrackUnit.h:323
TInterface::LocationNameButtonClick
void __fastcall LocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1139
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5806
TInterface::SaveMenuItem
TMenuItem * SaveMenuItem
Definition: InterfaceUnit.h:449
TInterface::GapSetting
@ GapSetting
Definition: InterfaceUnit.h:1018
TTrain::TimeTimeLocArrived
bool TimeTimeLocArrived
indicates whether has arrived (true) or not when ActionVectorEntryPtr->FormatType == TimeTimeLoc
Definition: TrainUnit.h:333
TInterface::ShowHideTTButton
TBitBtn * ShowHideTTButton
Definition: InterfaceUnit.h:159
TInterface::ScreenDownButton
TBitBtn * ScreenDownButton
Definition: InterfaceUnit.h:287
TTrain::LeadEntryPos
int LeadEntryPos
Definition: TrainUnit.h:366
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:752
TTrainController::LateArrivals
int LateArrivals
Definition: TrainUnit.h:833
TInterface::ShowHideStringGridMenuItem
TMenuItem * ShowHideStringGridMenuItem
Definition: InterfaceUnit.h:744
TInterface::DeleteOnePrefDirButton
TBitBtn * DeleteOnePrefDirButton
Definition: InterfaceUnit.h:152
TInterface::PauseEntryTTClockSpeed
float PauseEntryTTClockSpeed
rate at which the timetable clock runs on entry to the adjust routine - to restore if cancelled
Definition: InterfaceUnit.h:1345
TTrainController::ReplotTrains
void ReplotTrains(int Caller, TDisplay *Disp)
plot all trains on the display
Definition: TrainUnit.cpp:9596
TInterface::MetreVariableLabel
TLabel * MetreVariableLabel
Definition: InterfaceUnit.h:138
TInterface::AllEntriesTTListBoxTopPosition
int AllEntriesTTListBoxTopPosition
stores the TopIndex property when keys are used to select items in the TT edit panel
Definition: InterfaceUnit.h:1362
TInterface::SigImagePanel
TPanel * SigImagePanel
new at v2.3.0 for handed signals
Definition: InterfaceUnit.h:424
TTrain::FloatingTimetableString
AnsiString FloatingTimetableString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the timetable.
Definition: TrainUnit.cpp:7334
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:730
TInterface::CPGenFileButtonClick
void __fastcall CPGenFileButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:15103
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17680
TInterface::TTClockAdd10mButtonClick
void __fastcall TTClockAdd10mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14574
TRailGraphics::CouplingExit7
Graphics::TBitmap * CouplingExit7
Definition: GraphicUnit.h:557
TRailGraphics::SpeedBut73GrndBlackGlyph
Graphics::TBitmap * SpeedBut73GrndBlackGlyph
Definition: GraphicUnit.h:1073
TTrain::NewShuttleFromNonRepeatService
void NewShuttleFromNonRepeatService(int Caller, bool NoLogFlag)
Carry out the actions needed when a new shuttle service is created from a non-repeating (F-nshs) serv...
Definition: TrainUnit.cpp:6761
TTrain::AValue
double AValue
< only true when a train has become a follow-on service early and the follow-on service normally pass...
Definition: TrainUnit.h:414
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7661
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3118
TInterface::SkipTimetabledActionsMenuItem
TMenuItem * SkipTimetabledActionsMenuItem
Definition: InterfaceUnit.h:504
TTrainController::WriteTrainsToImage
void WriteTrainsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click) to write all trains to the image file.
Definition: TrainUnit.cpp:9614
TInterface::SpeedButton30
TSpeedButton * SpeedButton30
Definition: InterfaceUnit.h:572
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:131
TInterface::TTClockSpeedLabel
TLabel * TTClockSpeedLabel
Definition: InterfaceUnit.h:366
TTrack::FourAspectBuild
@ FourAspectBuild
Definition: TrackUnit.h:848
TInterface::ManualLCDownImage
TImage * ManualLCDownImage
Definition: InterfaceUnit.h:303
TInterface::SpeedButton146
TSpeedButton * SpeedButton146
Definition: InterfaceUnit.h:688
TTrainController::OpTimeToActMultiMapIterator
TOpTimeToActMultiMapIterator OpTimeToActMultiMapIterator
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:872
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:624
TInterface::NewEntryInPreparationFlag
bool NewEntryInPreparationFlag
true when a new timetable entry is being prepared in the timetable editor
Definition: InterfaceUnit.h:1253
TInterface::ConsecutiveSelfUpdates
int ConsecutiveSelfUpdates
counts time without an internet connection, cancels session for player if no contact for at least 5 m...
Definition: InterfaceUnit.h:1108
TInterface::EIdExceptionSource
AnsiString EIdExceptionSource
Definition: InterfaceUnit.h:1135
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TInterface::OAPanelLabel
TLabel * OAPanelLabel
Definition: InterfaceUnit.h:371
TInterface::GetVersion
UnicodeString GetVersion()
determined automatically from the project options 'Version Info'
Definition: InterfaceUnit.cpp:796
TInterface::OneEntryTimetableContents
AnsiString OneEntryTimetableContents
the current text in the large right hand timetable edit window
Definition: InterfaceUnit.h:1198
TInterface::SelectRect
TRect SelectRect
the rectangle in HLoc & VLoc terms set in Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1448
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:313
TTrain::ZeroPowerNoJoinedByMessage
bool ZeroPowerNoJoinedByMessage
Definition: TrainUnit.h:342
TInterface::LocationNameComboBox
TComboBox * LocationNameComboBox
the combobox that lists location names
Definition: InterfaceUnit.h:208
TInterface::ValidateTimetableKeyFlag
bool ValidateTimetableKeyFlag
Definition: InterfaceUnit.h:1335
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:750
TInterface::ExitOperationButton
TBitBtn * ExitOperationButton
Definition: InterfaceUnit.h:238
TInterface::TTLabel6
TLabel * TTLabel6
Definition: InterfaceUnit.h:381
TInterface::SpeedButton97
TSpeedButton * SpeedButton97
Definition: InterfaceUnit.h:639
TTrainController::SaveSessionContinuationAutoSigEntries
void SaveSessionContinuationAutoSigEntries(int Caller, std::ofstream &SessionFile)
save ContinuationAutoSigEntries to a session file
Definition: TrainUnit.cpp:15702
TInterface::JoinMultiplayerSessionMenuItemClick
void __fastcall JoinMultiplayerSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:24538
TInterface::SignalStopImage
TImage * SignalStopImage
Definition: InterfaceUnit.h:296
TInterface::SpeedButton13
TSpeedButton * SpeedButton13
Definition: InterfaceUnit.h:555
TInterface::OutputLog9
TLabel * OutputLog9
Definition: InterfaceUnit.h:337
TInterface::SetCaption
void SetCaption(int Caller)
Sets the railway and timetable titles at the top of the screen.
Definition: InterfaceUnit.cpp:19282
TInterface::SpeedButton27
TSpeedButton * SpeedButton27
Definition: InterfaceUnit.h:569
TOnePrefDir::ExternalClearPrefDirAnd4MultiMap
void ExternalClearPrefDirAnd4MultiMap()
Empty the existing preferred direction vector & map - for use by other classes.
Definition: TrackUnit.h:1386
TInterface::SetInitialPrefDirModeEditMenu
void SetInitialPrefDirModeEditMenu()
Enables or disables the initial Edit mode submenu items in PrefDir mode.
Definition: InterfaceUnit.cpp:22518
TInterface::MainScreenMouseMove
void __fastcall MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7671
TInterface::DistanceContinuing
@ DistanceContinuing
Definition: InterfaceUnit.h:1018
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:649
TInterface::PlayerOneSecondTimer
int PlayerOneSecondTimer
Definition: InterfaceUnit.h:1133
TInterface::CutTTEntryKeyFlag
bool CutTTEntryKeyFlag
Definition: InterfaceUnit.h:1329
TPrefDirElement::SetELinkPos
void SetELinkPos(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:340
TInterface::OneRailwayCouplingPair
TCouplingPair OneRailwayCouplingPair
Definition: InterfaceUnit.h:1104
TInterface::SigsOnLeftImage2
TImage * SigsOnLeftImage2
Definition: InterfaceUnit.h:318
TInterface::ChainEdit
TEdit * ChainEdit
Definition: InterfaceUnit.h:134
TInterface::SpeedButton109
TSpeedButton * SpeedButton109
Definition: InterfaceUnit.h:651
TInterface::CPAtLocCheckBox
TCheckBox * CPAtLocCheckBox
Definition: InterfaceUnit.h:279
TInterface::PasteTTEntryButtonClick
void __fastcall PasteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3901
TInterface::SpeedButton100
TSpeedButton * SpeedButton100
Definition: InterfaceUnit.h:642
TInterface::TestFunction
void TestFunction()
< used when change early to the next service (Fns, Fns-sh, Frh-sh or F-nshs) to advance the action po...
Definition: InterfaceUnit.cpp:22630
TInterface::ExportTTKeyFlag
bool ExportTTKeyFlag
Definition: InterfaceUnit.h:1339
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11533
TTrain::FirstHalfMove
bool FirstHalfMove
true when the train is on the first half of an element when it displays as fully on two elements....
Definition: TrainUnit.h:388
TInterface::MovingTrainPresentOnFlashingRoute
bool MovingTrainPresentOnFlashingRoute(int Caller)
Examines a flashing route (i.e. one being set) and returns true if a moving train is detected on it a...
Definition: InterfaceUnit.cpp:15910
TInterface::Level2TrackMode
enum TInterface::TLevel2TrackMode Level2TrackMode
TInterface::SpeedButton65
TSpeedButton * SpeedButton65
Definition: InterfaceUnit.h:607
TInterface::DeleteTTEntryKeyFlag
bool DeleteTTEntryKeyFlag
Definition: InterfaceUnit.h:1331
TTrainController::LatePasses
int LatePasses
Definition: TrainUnit.h:835
TInterface::SaveRailwayBaseModeButton
TBitBtn * SaveRailwayBaseModeButton
Save button at the top left hand corner of the screen when no mode is selected.
Definition: InterfaceUnit.h:94
TInterface::MPCPUserName
AnsiString MPCPUserName
Definition: InterfaceUnit.h:1136
TInterface::SelectBiDirPrefDirsMenuItem
TMenuItem * SelectBiDirPrefDirsMenuItem
Definition: InterfaceUnit.h:477
TInterface::UserGraphicReselectPanel
TPanel * UserGraphicReselectPanel
Definition: InterfaceUnit.h:521
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:99
TInterface::RotLeftMenuItem
TMenuItem * RotLeftMenuItem
Definition: InterfaceUnit.h:515
TInterface::TTClockxQuarterButtonClick
void __fastcall TTClockxQuarterButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14496
TTrainController::SSHigh
bool SSHigh
Definition: TrainUnit.h:805
TInterface::TextOrUserGraphicGridVal
int TextOrUserGraphicGridVal
stores the text alignment grid value, cycles forwards through 1, 2, 4, 8 & 16 each time the text grid...
Definition: InterfaceUnit.h:1407
TimeLoc
@ TimeLoc
Definition: TrainUnit.h:66
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:195
TInterface::FileMenu
TMenuItem * FileMenu
Definition: InterfaceUnit.h:446
TTrainController::AvHoursIntValue
int AvHoursIntValue
Input in MTBFEditBox in timetable hours, min value is 1 and max is 10,000. Here because performance f...
Definition: TrainUnit.h:856
TTrainController::CrashedTrains
int CrashedTrains
Definition: TrainUnit.h:827
TInterface::OutputLog3MouseDown
void __fastcall OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:13754
TInterface::SpeedConversionPanel
TPanel * SpeedConversionPanel
Definition: InterfaceUnit.h:141
TTrainController::TTEditPanelVisible
bool TTEditPanelVisible
new at v2.6.0 so potential error message only shows in TTEdit mode
Definition: TrainUnit.h:803
TTrain::LogAction
void LogAction(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionType ActionType, AnsiString LocationName, TDateTime TimetableNonRepeatTime, bool Warning)
Send a message to the performance log and performance file, and if the message is flagged as a warnin...
Definition: TrainUnit.cpp:5283
TInterface::SpeedButton22
TSpeedButton * SpeedButton22
Definition: InterfaceUnit.h:564
TTextHandler::SaveText
void SaveText(int Caller, std::ofstream &VecFile)
save the railway's text to VecFile
Definition: TextUnit.cpp:335
TInterface::TwoLocationNameLabel
TLabel * TwoLocationNameLabel
Definition: InterfaceUnit.h:694
TTrain::StoppedAtSignal
bool StoppedAtSignal
Definition: TrainUnit.h:482
TInterface::SpeedButton130
TSpeedButton * SpeedButton130
Definition: InterfaceUnit.h:672
TTrack::GetGapHLoc
int GetGapHLoc()
Definition: TrackUnit.h:852
TInterface::ResetDefaultLengthButton
TBitBtn * ResetDefaultLengthButton
Definition: InterfaceUnit.h:113
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:140
TInterface::PauseEntryRestartTime
double PauseEntryRestartTime
time value of the timetable restart time (as a double) on entry to pause mode
Definition: InterfaceUnit.h:1342
TInterface::MajorDelaysMenuItem
TMenuItem * MajorDelaysMenuItem
Definition: InterfaceUnit.h:755
TInterface::SelectBiDirPrefDirsMenuItemClick
void __fastcall SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10869
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4259
TInterface::SigsOnRightImage2
TImage * SigsOnRightImage2
Definition: InterfaceUnit.h:320
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:794
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4557
TTrain::SelSkipString
UnicodeString SelSkipString
the selected timetable string when skipping timetabled events
Definition: TrainUnit.h:509
TInterface::MultiplayerHostSessionMenuItem
TMenuItem * MultiplayerHostSessionMenuItem
Definition: InterfaceUnit.h:720
TInterface::AddTrack
@ AddTrack
Definition: InterfaceUnit.h:1018
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7524
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1955
TInterface::ClearAllMenuItem
TMenuItem * ClearAllMenuItem
Definition: InterfaceUnit.h:453
API
a class which handles the fetching of information from the ROS interface via pointers to variables of...
Definition: API.h:30
TTrain::TrainSkippedEvents
int TrainSkippedEvents
stores the pointer increment from the current action in ActionVector for skipped actions when a depar...
Definition: TrainUnit.h:376
TTrainController::THCandTrainPosParam
std::pair< AnsiString, int > THCandTrainPosParam
Definition: TrainUnit.h:776
TInterface::SaveImageNoGridMenuItem
TMenuItem * SaveImageNoGridMenuItem
Definition: InterfaceUnit.h:489
TInterface::SelectMenuItemClick
void __fastcall SelectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9715
TInterface::PlayerHandshakingActions
void PlayerHandshakingActions()
called in ClockTimer2 if player multiplay in progress
Definition: InterfaceUnit.cpp:25451
TInterface::BypassPDCrossoverMismatch
bool BypassPDCrossoverMismatch(int Caller, int HLoc, int VLoc)
Check for bidir crossover between two single PD lines. Used in PD check function.
Definition: InterfaceUnit.cpp:11437
TRailGraphics::SpeedBut74NormBlackGlyph
Graphics::TBitmap * SpeedBut74NormBlackGlyph
Definition: GraphicUnit.h:1066
TInterface::StartY
int StartY
the mouse position in terms of pixels when an item of text is being selected for moving
Definition: InterfaceUnit.h:1399
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:65
TInterface::UpdateOperatorActionPanel
void UpdateOperatorActionPanel(int Caller)
Called every 5 secs to update the panel (if visible)
Definition: InterfaceUnit.cpp:22836
TInterface::TextBoxKeyPress
void __fastcall TextBoxKeyPress(TObject *Sender, char &Key)
Definition: InterfaceUnit.cpp:1094
TInterface::SaveTimetableToSessionFile
bool SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
Called during a session save to save the current timetable in the session file, true if successful.
Definition: InterfaceUnit.cpp:20510
TInterface::MPHPCancelButton
TButton * MPHPCancelButton
Definition: InterfaceUnit.h:724
TInterface::SpeedButton71
TSpeedButton * SpeedButton71
Definition: InterfaceUnit.h:613
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7319
TTrain::OpTimeToAct
float OpTimeToAct
in minutes: new at v2.2.0 for operator time to act panel. Calculated in UpdateTrain,...
Definition: TrainUnit.h:448
TInterface::DeleteAllPrefDirButtonClick
void __fastcall DeleteAllPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1993
Platform
@ Platform
Definition: TrackUnit.h:65
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1368
TInterface::RlyFile
bool RlyFile
indicates that a loaded railway file is ready for operation, i.e. is a valid .rly file
Definition: InterfaceUnit.h:1269
TInterface::RestartSessionOperMode
@ RestartSessionOperMode
Definition: InterfaceUnit.h:986
TInterface::PreferredRouteFlag
bool PreferredRouteFlag
used to select either ConvertAndAddPreferredRouteSearchVector or ConvertAndAddNonPreferredRouteSearch...
Definition: InterfaceUnit.h:1263
TInterface::SkipTTActionsListBoxMouseUp
void __fastcall SkipTTActionsListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12247
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:756
TInterface::TextMoveHPos
int TextMoveHPos
Definition: InterfaceUnit.h:1411
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4582
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:702
TInterface::PowerTopLabel
TLabel * PowerTopLabel
Definition: InterfaceUnit.h:223
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:770
TInterface::SpeedButton129
TSpeedButton * SpeedButton129
Definition: InterfaceUnit.h:671
TInterface::RepairFailedTrainMenuItem
TMenuItem * RepairFailedTrainMenuItem
Definition: InterfaceUnit.h:517
TUtilities::CheckAndCompareFileString
bool CheckAndCompareFileString(std::ifstream &InFile, AnsiString InString)
checks that the value is a string ('0' or CR accepted as delimiters) and is the same as InString,...
Definition: Utilities.cpp:474
TInterface::CutTTEntryButton
TButton * CutTTEntryButton
Definition: InterfaceUnit.h:166
TInterface::AZOrderKeyFlag
bool AZOrderKeyFlag
Definition: InterfaceUnit.h:1333
TInterface::MPCPLabel7
TLabel * MPCPLabel7
Definition: InterfaceUnit.h:734
TInterface::MileEdit
TEdit * MileEdit
Definition: InterfaceUnit.h:133
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1292
TInterface::TTClockx8ButtonClick
void __fastcall TTClockx8ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14420
TInterface::SetLevel2OperMode
void SetLevel2OperMode(int Caller)
Sets the Level2OperMode user mode, using the Level2OperMode variable to determine the mode.
Definition: InterfaceUnit.cpp:17408
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9473
TInterface::RestoreTTButton
TButton * RestoreTTButton
Definition: InterfaceUnit.h:182
TInterface::SaveConfigFile
void SaveConfigFile(int Caller)
Save Config.txt file to disk when program ends.
Definition: InterfaceUnit.cpp:15397
TTrain::TimetableFinished
bool TimetableFinished
set when there are no more timetable actions
Definition: TrainUnit.h:408
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1765
TInterface::EraseLocationNameText
bool EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
Erase a location name (providing it exists in LocationNameMultiMap) from TextVector,...
Definition: InterfaceUnit.cpp:22563
TInterface::PrefDirKey
TImage * PrefDirKey
information panel displayed when setting preferred directions
Definition: InterfaceUnit.h:307
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:63
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15932
TActionVectorEntry::Command
AnsiString Command
Definition: TrainUnit.h:124
TInterface::SpeedButton138
TSpeedButton * SpeedButton138
Definition: InterfaceUnit.h:680
TTrain::RepeatShuttleOrRemainHere
void RepeatShuttleOrRemainHere(int Caller, bool NoLogFlag)
Carry out the actions needed to create either a new shuttle service or (if all repeats have finished)...
Definition: TrainUnit.cpp:6806
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:796
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:148
TInterface::DeleteAllPrefDirButton
TBitBtn * DeleteAllPrefDirButton
Definition: InterfaceUnit.h:153
TInterface::SpeedButton117
TSpeedButton * SpeedButton117
Definition: InterfaceUnit.h:659
TTrain::SignallerStoppingFlag
bool SignallerStoppingFlag
set when the signaller stop command has been given
Definition: TrainUnit.h:400
TInterface::SelectPrefDir
TOnePrefDir * SelectPrefDir
Pref Dir elements in a selected region.
Definition: InterfaceUnit.h:1443
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TInterface::SpeedButton39
TSpeedButton * SpeedButton39
Definition: InterfaceUnit.h:581
TTrack::BuildBasicElementFromSpeedTag
TTrackElement BuildBasicElementFromSpeedTag(int Caller, int SpeedTag)
Return a basic track element from the SpeedTag new at v2.2.0 - needed because Interface doesn't have ...
Definition: TrackUnit.h:907
TInterface::TTStartTimeBox
TEdit * TTStartTimeBox
edit box that displays the timetable start time
Definition: InterfaceUnit.h:206
TInterface::AddPrefDirButtonClick
void __fastcall AddPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1964
TInterface::ShiftKey
bool ShiftKey
true when the SHIFT key is pressed (see also CtrlKey)
Definition: InterfaceUnit.h:1283
TInterface::MPCPLabel3
TLabel * MPCPLabel3
Definition: InterfaceUnit.h:716
TInterface::MPHPLoadCouplingFileButton
TButton * MPHPLoadCouplingFileButton
Definition: InterfaceUnit.h:725
TTrainController::SigSLow
bool SigSLow
Message flags in TT checks to stop being given twice.
Definition: TrainUnit.h:805
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:611
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6343
TInterface::AddMinsButtonClick
void __fastcall AddMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3623
RemoveTrain
@ RemoveTrain
Definition: TrainUnit.h:53
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3616
TInterface::HostHandshakingActions
void HostHandshakingActions()
called in ClockTimer2 if host multiplay in progress
Definition: InterfaceUnit.cpp:24191
TInterface::FontButtonClick
void __fastcall FontButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1889
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TInterface::PlayerAwaitingHostStartFlag
bool PlayerAwaitingHostStartFlag
Definition: InterfaceUnit.h:1146
TInterface::SigAspectButtonClick
void __fastcall SigAspectButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1850
TTrack::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:760
TInterface::SetLevel2TrackMode
void SetLevel2TrackMode(int Caller)
Sets the Level2TrackMode user mode, using the Level2TrackMode variable to determine the mode.
Definition: InterfaceUnit.cpp:16616
TTrainController::SetWarningFlags
void SetWarningFlags(int Caller)
This sets all the warning flags (CrashWarning, DerailWarning etc) to their required states after a se...
Definition: TrainUnit.cpp:19810
TInterface::TwoLocationNameButtonClick
void __fastcall TwoLocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:15045
TInterface::None
@ None
Definition: InterfaceUnit.h:1024
TInterface::SpeedButton87
TSpeedButton * SpeedButton87
Definition: InterfaceUnit.h:629
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TInterface::FormClose
void __fastcall FormClose(TObject *Sender, TCloseAction &Action)
Definition: InterfaceUnit.cpp:13145
TInterface::SigAspectButton
TBitBtn * SigAspectButton
Definition: InterfaceUnit.h:110
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11002
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:736
TInterface::PreviousTTEntryKeyFlag
bool PreviousTTEntryKeyFlag
Definition: InterfaceUnit.h:1324
TInterface::CPEditDepRange
TEdit * CPEditDepRange
Definition: InterfaceUnit.h:281
TInterface::SpeedButton127
TSpeedButton * SpeedButton127
Definition: InterfaceUnit.h:669
TTrainController::TotEarlyPassMins
float TotEarlyPassMins
Definition: TrainUnit.h:819
TTrainController::OpTimeToActMultiMap
TOpTimeToActMultiMap OpTimeToActMultiMap
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:870
TInterface::SelectBitmapMouseLocY
int SelectBitmapMouseLocY
see above
Definition: InterfaceUnit.h:1386
TInterface::RemovePlayerFromStringGridAndInfoVector
void RemovePlayerFromStringGridAndInfoVector(int Caller, AnsiString PlayerUserName)
utility to clear user name from string grid & infovector (used several times)
Definition: InterfaceUnit.cpp:25403
TTrain::BrakeRate
double BrakeRate
the current train brake rate
Definition: TrainUnit.h:432
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:148
TPrefDirElement::SetCheckCount
void SetCheckCount(int ChkCnt)
Definition: TrackUnit.h:328
TTrack::GapFlashFlag
bool GapFlashFlag
true when a pair of connected gaps is flashing
Definition: TrackUnit.h:734
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:620
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TInterface::StartX
int StartX
Definition: InterfaceUnit.h:1399
TrainUnit.h
PassTime
@ PassTime
Definition: TrainUnit.h:67
TTrack::LevelCrossingBarrierUpFlashDuration
float LevelCrossingBarrierUpFlashDuration
duration of the flash period when level crossing closing to trains
Definition: TrackUnit.h:754
TTrainController::IncorrectExits
int IncorrectExits
Definition: TrainUnit.h:832
TUtilities::SetLocaleResultOK
bool SetLocaleResultOK
flag to indicate whether the call to setlocale() in InterfaceUnit.cpp succeeded or not
Definition: Utilities.h:47
TInterface::SelectLengthsFlag
bool SelectLengthsFlag
true when 'Set lengths &/or speeds' selected in the 'Edit' menu
Definition: InterfaceUnit.h:1279
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:89
TRailGraphics::LockedRouteCancelPtr
Graphics::TBitmap * LockedRouteCancelPtr[10]
for locked route cancel graphic, 1 for each of 8 links, 0 & 5 included as for direction
Definition: GraphicUnit.h:1052
TInterface::MultiplayerMenu
TMenuItem * MultiplayerMenu
Definition: InterfaceUnit.h:702
TTextItem::TextString
AnsiString TextString
the text string
Definition: TextUnit.h:46
TInterface::TrackOKButton
TBitBtn * TrackOKButton
Definition: InterfaceUnit.h:100
TInterface::SpeedButton23
TSpeedButton * SpeedButton23
Definition: InterfaceUnit.h:565
TInterface::RailwayTitle
AnsiString RailwayTitle
Definition: InterfaceUnit.h:1202
TInterface::TNumHVPair
std::pair< unsigned char, THVShortPair > TNumHVPair
Definition: InterfaceUnit.h:1086
TDisplay::Rectangle
void Rectangle(int Caller, int HPos, int VPos, TColor Col, int Size, int Width)
Plot a rectangle at the defined position with colour Col & size defined by Size.
Definition: DisplayUnit.cpp:154
TInterface::SpeedButton20
TSpeedButton * SpeedButton20
Definition: InterfaceUnit.h:562
API.h
File containing classes and methods for broadcasting ROS status data.
TInterface::CheckInterface
bool CheckInterface(int Caller, std::ifstream &SessionFile)
Check the interface part of a session file & return false for error, called during SessionFileIntegri...
Definition: InterfaceUnit.cpp:20278
TInterface::PreStart
@ PreStart
Definition: InterfaceUnit.h:1008
TRailGraphics::SolidCircleGreen
Graphics::TBitmap * SolidCircleGreen
Definition: GraphicUnit.h:563
AboutForm
TAboutForm * AboutForm
Definition: AboutUnit.cpp:47
TInterface::SpeedButton137
TSpeedButton * SpeedButton137
Definition: InterfaceUnit.h:679
TInterface::ExitTTModeButton
TBitBtn * ExitTTModeButton
Definition: InterfaceUnit.h:160
TTrain::SetTrainMovementValues
void SetTrainMovementValues(int Caller, int TrackVectorPosition, int EntryPos)
Calculates train speeds and times for the element that the train is about to enter....
Definition: TrainUnit.cpp:3622
TActionVectorEntry::Warning
bool Warning
if set triggers an alert in the warning panel when the action is reached
Definition: TrainUnit.h:130
TInterface::OverallSpeedLimit
int OverallSpeedLimit
and the overall speed limit, if the speed limits vary across the selection the value is set to -1
Definition: InterfaceUnit.h:1374
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11467
TInterface::SpeedButton78
TSpeedButton * SpeedButton78
Definition: InterfaceUnit.h:620
TRailGraphics::SpeedBut75GrndBlackGlyph
Graphics::TBitmap * SpeedBut75GrndBlackGlyph
Definition: GraphicUnit.h:1075
TTrainDataEntry::ServiceReference
AnsiString ServiceReference
Definition: TrainUnit.h:209
TInterface::PowerEditBox
TEdit * PowerEditBox
Definition: InterfaceUnit.h:222
TInterface::TimetableHandler
void TimetableHandler()
Called during timetable editing whenever a change is made to the timetable, sets all the timetable bu...
Definition: InterfaceUnit.cpp:5367
TTrain::SignallerChangeTrainDirection
void SignallerChangeTrainDirection(int Caller)
Unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd.
Definition: TrainUnit.cpp:7060
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TInterface::CancelSelectionMenuItem
TMenuItem * CancelSelectionMenuItem
Definition: InterfaceUnit.h:478
TTrain::ZeroPowerNoRearSplitMessage
bool ZeroPowerNoRearSplitMessage
Definition: TrainUnit.h:340
TInterface::SpeedButton68
TSpeedButton * SpeedButton68
Definition: InterfaceUnit.h:610
TInterface::HostInSessionFlag
bool HostInSessionFlag
Definition: InterfaceUnit.h:1140
TInterface::LoadSession
void LoadSession(int Caller)
Load a session file.
Definition: InterfaceUnit.cpp:19720
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18726
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TInterface::SigRouteStartMarker
TGraphicElement * SigRouteStartMarker
Definition: InterfaceUnit.h:1430
TInterface::SetGapsButtonClick
void __fastcall SetGapsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1035
TInterface::SignallerControlStopMenuItemClick
void __fastcall SignallerControlStopMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12804
TInterface::PrefDirSelecting
@ PrefDirSelecting
Definition: InterfaceUnit.h:1013
TInterface::TimetableDialog
TOpenDialog * TimetableDialog
Definition: InterfaceUnit.h:528
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11031
TInterface::MoveTTEntryUpButton
TButton * MoveTTEntryUpButton
Definition: InterfaceUnit.h:169
TInterface::SigPrefConsecButton
TBitBtn * SigPrefConsecButton
Definition: InterfaceUnit.h:231
TInterface::PlayerReadyToBeginFlag
bool PlayerReadyToBeginFlag
Definition: InterfaceUnit.h:1144
TInterface::MPCPReadyToBeginButtonClick
void __fastcall MPCPReadyToBeginButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:24655
TInterface::RotateMenuItem
TMenuItem * RotateMenuItem
Definition: InterfaceUnit.h:473
TInterface::SpeedButton33
TSpeedButton * SpeedButton33
Definition: InterfaceUnit.h:575
TInterface::MultiplayerPlayerPanel
TPanel * MultiplayerPlayerPanel
Definition: InterfaceUnit.h:711
TInterface::TTClockxSixteenthButtonClick
void __fastcall TTClockxSixteenthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14534
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:670
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TUtilities::Clock2Stopped
bool Clock2Stopped
when true the main loop - Interface->ClockTimer2 - is stopped
Definition: Utilities.h:43
TTrainController::MRSHigh
bool MRSHigh
Definition: TrainUnit.h:805
TInterface::FlipMenuItem
TMenuItem * FlipMenuItem
Definition: InterfaceUnit.h:471
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6244
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:157
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:66
TInterface::SessionFileIntegrityCheck
bool SessionFileIntegrityCheck(int Caller, AnsiString FileName)
Checks session file integrity prior to loading, true for success.
Definition: InterfaceUnit.cpp:21069
TInterface::TrainFailedImage
TImage * TrainFailedImage
Definition: InterfaceUnit.h:302
TTrain::NotInService
bool NotInService
Definition: TrainUnit.h:483
TInterface::RotLeftMenuItemClick
void __fastcall RotLeftMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10513
TInterface::SpeedButton14
TSpeedButton * SpeedButton14
Definition: InterfaceUnit.h:556
TInterface::ExitTrackButton
TBitBtn * ExitTrackButton
Definition: InterfaceUnit.h:111
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:728
TInterface::SpeedButton110
TSpeedButton * SpeedButton110
Definition: InterfaceUnit.h:652
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TInterface::OutputLog10
TLabel * OutputLog10
Definition: InterfaceUnit.h:338
TInterface::SESSION_DIR_NAME
static const UnicodeString SESSION_DIR_NAME
Definition: InterfaceUnit.h:1000
TInterface::PasteTTEntryKeyFlag
bool PasteTTEntryKeyFlag
Definition: InterfaceUnit.h:1330
TInterface::FileChangedFlag
bool FileChangedFlag
true when a loaded railway file has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:1235
TInterface::TooShortMessageSentFlag
bool TooShortMessageSentFlag
indicates that the length of a location element might be too short (<50m), so it won't be given again
Definition: InterfaceUnit.h:1299
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:142
TInterface::CutTTEntryButtonClick
void __fastcall CutTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3828
TInterface::AutoSigsButtonClick
void __fastcall AutoSigsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2115
TRailGraphics::SpeedBut69GrndBlackGlyph
Graphics::TBitmap * SpeedBut69GrndBlackGlyph
Definition: GraphicUnit.h:1069
Signaller
@ Signaller
Definition: TrainUnit.h:60
TRailGraphics::bmRedRect
Graphics::TBitmap * bmRedRect
Definition: GraphicUnit.h:527
TInterface::SaveOperatingImageMenuItemClick
void __fastcall SaveOperatingImageMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2930
TRailGraphics::smYellow
Graphics::TBitmap * smYellow
Definition: GraphicUnit.h:902
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TInterface::ConstructRoute
TOneRoute * ConstructRoute
the route under construction
Definition: InterfaceUnit.h:1445
TInterface::SpeedButton118
TSpeedButton * SpeedButton118
Definition: InterfaceUnit.h:660
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10283
TTrain::TreatPassAsTimeLocDeparture
bool TreatPassAsTimeLocDeparture
< indicates failure
Definition: TrainUnit.h:412
Bridge
@ Bridge
Definition: TrackUnit.h:65
TTrack::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:758
TInterface::DirOpenError
bool DirOpenError
true when one of the program subfolders doesn't already exist and can't be created
Definition: InterfaceUnit.h:1229
TInterface::CutMenuItemClick
void __fastcall CutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9807
TInterface::SpeedButton38
TSpeedButton * SpeedButton38
Definition: InterfaceUnit.h:580
TInterface::ShowHideStringGridMenuItemClick
void __fastcall ShowHideStringGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:25434
TInterface::ResetCurrentSpeedButton
void ResetCurrentSpeedButton(int Caller)
Resets the CurrentSpeedButton variable to zero and the 'Down' property to false.
Definition: InterfaceUnit.cpp:15897
TInterface::SpeedButton102
TSpeedButton * SpeedButton102
Definition: InterfaceUnit.h:644
TTrain::TimetableMaxRunningSpeed
double TimetableMaxRunningSpeed
the maximum train running speed when in timetable mode (see int SignallerMaxSpeed for signaller contr...
Definition: TrainUnit.h:424
TInterface::SpeedButton99
TSpeedButton * SpeedButton99
Definition: InterfaceUnit.h:641
clB0G0R0
#define clB0G0R0
Definition: GraphicUnit.h:36
TInterface::CPDeparturesCheckBox
TCheckBox * CPDeparturesCheckBox
Definition: InterfaceUnit.h:278
Buffers
@ Buffers
Definition: TrackUnit.h:65
TInterface::SelectGraphic
@ SelectGraphic
Definition: InterfaceUnit.h:1018
TTextHandler::TextMove
void TextMove(int Caller, int HPosInput, int VPosInput, int &TextItem, int &TextMoveHPos, int &TextMoveVPos, bool &TextFoundFlag)
Definition: TextUnit.cpp:209
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:55
clFrontCodeTimetable
#define clFrontCodeTimetable
Definition: GraphicUnit.h:296
TTrack::UserGraphicPresentAtHV
bool UserGraphicPresentAtHV(int Caller, int HPos, int VPos, int &UGIVectorPos)
checks if a user graphic present
Definition: TrackUnit.h:829
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11491
TInterface::ExitTTModeButtonClick
void __fastcall ExitTTModeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4730
TInterface::MirrorMenuItemClick
void __fastcall MirrorMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9967
TInterface::SpeedButton11
TSpeedButton * SpeedButton11
Definition: InterfaceUnit.h:553
TInterface::RouteNotStarted
@ RouteNotStarted
Definition: InterfaceUnit.h:1024
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4494
TInterface::SaveImageAndGridMenuItem
TMenuItem * SaveImageAndGridMenuItem
Definition: InterfaceUnit.h:490
TInterface::SpeedButton48
TSpeedButton * SpeedButton48
Definition: InterfaceUnit.h:590
TInterface::WhiteBgndMenuItemClick
void __fastcall WhiteBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13903
TInterface::GetTrainIDOrContinuationPosition
bool GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &ContinuationPos)
Used in actions due panel to identify the train or continuation.
Definition: InterfaceUnit.cpp:5023